Initial OpenECOMP policy/engine commit
[policy/engine.git] / ecomp-sdk-app / src / main / webapp / app / fusion / external / angular-1.5 / 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.0
9194  * (c) 2010-2016 Google, Inc. http://angularjs.org
9195  * License: MIT
9196  */
9197 (function(window, document){
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.0/' +
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  * @description
9367  *
9368  * # ng (core module)
9369  * The ng module is loaded by default when an AngularJS application is started. The module itself
9370  * contains the essential components for an AngularJS application to function. The table below
9371  * lists a high level breakdown of each of the services/factories, filters, directives and testing
9372  * components available within this core module.
9373  *
9374  * <div doc-module-components="ng"></div>
9375  */
9376
9377 var REGEX_STRING_REGEXP = /^\/(.+)\/([a-z]*)$/;
9378
9379 // The name of a form control's ValidityState property.
9380 // This is used so that it's possible for internal tests to create mock ValidityStates.
9381 var VALIDITY_STATE_PROPERTY = 'validity';
9382
9383 var hasOwnProperty = Object.prototype.hasOwnProperty;
9384
9385 var lowercase = function(string) {return isString(string) ? string.toLowerCase() : string;};
9386 var uppercase = function(string) {return isString(string) ? string.toUpperCase() : string;};
9387
9388
9389 var manualLowercase = function(s) {
9390   /* jshint bitwise: false */
9391   return isString(s)
9392       ? s.replace(/[A-Z]/g, function(ch) {return String.fromCharCode(ch.charCodeAt(0) | 32);})
9393       : s;
9394 };
9395 var manualUppercase = function(s) {
9396   /* jshint bitwise: false */
9397   return isString(s)
9398       ? s.replace(/[a-z]/g, function(ch) {return String.fromCharCode(ch.charCodeAt(0) & ~32);})
9399       : s;
9400 };
9401
9402
9403 // String#toLowerCase and String#toUpperCase don't produce correct results in browsers with Turkish
9404 // locale, for this reason we need to detect this case and redefine lowercase/uppercase methods
9405 // with correct but slower alternatives. See https://github.com/angular/angular.js/issues/11387
9406 if ('i' !== 'I'.toLowerCase()) {
9407   lowercase = manualLowercase;
9408   uppercase = manualUppercase;
9409 }
9410
9411
9412 var
9413     msie,             // holds major version number for IE, or NaN if UA is not IE.
9414     jqLite,           // delay binding since jQuery could be loaded after us.
9415     jQuery,           // delay binding
9416     slice             = [].slice,
9417     splice            = [].splice,
9418     push              = [].push,
9419     toString          = Object.prototype.toString,
9420     getPrototypeOf    = Object.getPrototypeOf,
9421     ngMinErr          = minErr('ng'),
9422
9423     /** @name angular */
9424     angular           = window.angular || (window.angular = {}),
9425     angularModule,
9426     uid               = 0;
9427
9428 /**
9429  * documentMode is an IE-only property
9430  * http://msdn.microsoft.com/en-us/library/ie/cc196988(v=vs.85).aspx
9431  */
9432 msie = document.documentMode;
9433
9434
9435 /**
9436  * @private
9437  * @param {*} obj
9438  * @return {boolean} Returns true if `obj` is an array or array-like object (NodeList, Arguments,
9439  *                   String ...)
9440  */
9441 function isArrayLike(obj) {
9442
9443   // `null`, `undefined` and `window` are not array-like
9444   if (obj == null || isWindow(obj)) return false;
9445
9446   // arrays, strings and jQuery/jqLite objects are array like
9447   // * jqLite is either the jQuery or jqLite constructor function
9448   // * we have to check the existence of jqLite first as this method is called
9449   //   via the forEach method when constructing the jqLite object in the first place
9450   if (isArray(obj) || isString(obj) || (jqLite && obj instanceof jqLite)) return true;
9451
9452   // Support: iOS 8.2 (not reproducible in simulator)
9453   // "length" in obj used to prevent JIT error (gh-11508)
9454   var length = "length" in Object(obj) && obj.length;
9455
9456   // NodeList objects (with `item` method) and
9457   // other objects with suitable length characteristics are array-like
9458   return isNumber(length) &&
9459     (length >= 0 && ((length - 1) in obj || obj instanceof Array) || typeof obj.item == 'function');
9460
9461 }
9462
9463 /**
9464  * @ngdoc function
9465  * @name angular.forEach
9466  * @module ng
9467  * @kind function
9468  *
9469  * @description
9470  * Invokes the `iterator` function once for each item in `obj` collection, which can be either an
9471  * object or an array. The `iterator` function is invoked with `iterator(value, key, obj)`, where `value`
9472  * is the value of an object property or an array element, `key` is the object property key or
9473  * array element index and obj is the `obj` itself. Specifying a `context` for the function is optional.
9474  *
9475  * It is worth noting that `.forEach` does not iterate over inherited properties because it filters
9476  * using the `hasOwnProperty` method.
9477  *
9478  * Unlike ES262's
9479  * [Array.prototype.forEach](http://www.ecma-international.org/ecma-262/5.1/#sec-15.4.4.18),
9480  * Providing 'undefined' or 'null' values for `obj` will not throw a TypeError, but rather just
9481  * return the value provided.
9482  *
9483    ```js
9484      var values = {name: 'misko', gender: 'male'};
9485      var log = [];
9486      angular.forEach(values, function(value, key) {
9487        this.push(key + ': ' + value);
9488      }, log);
9489      expect(log).toEqual(['name: misko', 'gender: male']);
9490    ```
9491  *
9492  * @param {Object|Array} obj Object to iterate over.
9493  * @param {Function} iterator Iterator function.
9494  * @param {Object=} context Object to become context (`this`) for the iterator function.
9495  * @returns {Object|Array} Reference to `obj`.
9496  */
9497
9498 function forEach(obj, iterator, context) {
9499   var key, length;
9500   if (obj) {
9501     if (isFunction(obj)) {
9502       for (key in obj) {
9503         // Need to check if hasOwnProperty exists,
9504         // as on IE8 the result of querySelectorAll is an object without a hasOwnProperty function
9505         if (key != 'prototype' && key != 'length' && key != 'name' && (!obj.hasOwnProperty || obj.hasOwnProperty(key))) {
9506           iterator.call(context, obj[key], key, obj);
9507         }
9508       }
9509     } else if (isArray(obj) || isArrayLike(obj)) {
9510       var isPrimitive = typeof obj !== 'object';
9511       for (key = 0, length = obj.length; key < length; key++) {
9512         if (isPrimitive || key in obj) {
9513           iterator.call(context, obj[key], key, obj);
9514         }
9515       }
9516     } else if (obj.forEach && obj.forEach !== forEach) {
9517         obj.forEach(iterator, context, obj);
9518     } else if (isBlankObject(obj)) {
9519       // createMap() fast path --- Safe to avoid hasOwnProperty check because prototype chain is empty
9520       for (key in obj) {
9521         iterator.call(context, obj[key], key, obj);
9522       }
9523     } else if (typeof obj.hasOwnProperty === 'function') {
9524       // Slow path for objects inheriting Object.prototype, hasOwnProperty check needed
9525       for (key in obj) {
9526         if (obj.hasOwnProperty(key)) {
9527           iterator.call(context, obj[key], key, obj);
9528         }
9529       }
9530     } else {
9531       // Slow path for objects which do not have a method `hasOwnProperty`
9532       for (key in obj) {
9533         if (hasOwnProperty.call(obj, key)) {
9534           iterator.call(context, obj[key], key, obj);
9535         }
9536       }
9537     }
9538   }
9539   return obj;
9540 }
9541
9542 function forEachSorted(obj, iterator, context) {
9543   var keys = Object.keys(obj).sort();
9544   for (var i = 0; i < keys.length; i++) {
9545     iterator.call(context, obj[keys[i]], keys[i]);
9546   }
9547   return keys;
9548 }
9549
9550
9551 /**
9552  * when using forEach the params are value, key, but it is often useful to have key, value.
9553  * @param {function(string, *)} iteratorFn
9554  * @returns {function(*, string)}
9555  */
9556 function reverseParams(iteratorFn) {
9557   return function(value, key) {iteratorFn(key, value);};
9558 }
9559
9560 /**
9561  * A consistent way of creating unique IDs in angular.
9562  *
9563  * Using simple numbers allows us to generate 28.6 million unique ids per second for 10 years before
9564  * we hit number precision issues in JavaScript.
9565  *
9566  * Math.pow(2,53) / 60 / 60 / 24 / 365 / 10 = 28.6M
9567  *
9568  * @returns {number} an unique alpha-numeric string
9569  */
9570 function nextUid() {
9571   return ++uid;
9572 }
9573
9574
9575 /**
9576  * Set or clear the hashkey for an object.
9577  * @param obj object
9578  * @param h the hashkey (!truthy to delete the hashkey)
9579  */
9580 function setHashKey(obj, h) {
9581   if (h) {
9582     obj.$$hashKey = h;
9583   } else {
9584     delete obj.$$hashKey;
9585   }
9586 }
9587
9588
9589 function baseExtend(dst, objs, deep) {
9590   var h = dst.$$hashKey;
9591
9592   for (var i = 0, ii = objs.length; i < ii; ++i) {
9593     var obj = objs[i];
9594     if (!isObject(obj) && !isFunction(obj)) continue;
9595     var keys = Object.keys(obj);
9596     for (var j = 0, jj = keys.length; j < jj; j++) {
9597       var key = keys[j];
9598       var src = obj[key];
9599
9600       if (deep && isObject(src)) {
9601         if (isDate(src)) {
9602           dst[key] = new Date(src.valueOf());
9603         } else if (isRegExp(src)) {
9604           dst[key] = new RegExp(src);
9605         } else if (src.nodeName) {
9606           dst[key] = src.cloneNode(true);
9607         } else if (isElement(src)) {
9608           dst[key] = src.clone();
9609         } else {
9610           if (!isObject(dst[key])) dst[key] = isArray(src) ? [] : {};
9611           baseExtend(dst[key], [src], true);
9612         }
9613       } else {
9614         dst[key] = src;
9615       }
9616     }
9617   }
9618
9619   setHashKey(dst, h);
9620   return dst;
9621 }
9622
9623 /**
9624  * @ngdoc function
9625  * @name angular.extend
9626  * @module ng
9627  * @kind function
9628  *
9629  * @description
9630  * Extends the destination object `dst` by copying own enumerable properties from the `src` object(s)
9631  * to `dst`. You can specify multiple `src` objects. If you want to preserve original objects, you can do so
9632  * by passing an empty object as the target: `var object = angular.extend({}, object1, object2)`.
9633  *
9634  * **Note:** Keep in mind that `angular.extend` does not support recursive merge (deep copy). Use
9635  * {@link angular.merge} for this.
9636  *
9637  * @param {Object} dst Destination object.
9638  * @param {...Object} src Source object(s).
9639  * @returns {Object} Reference to `dst`.
9640  */
9641 function extend(dst) {
9642   return baseExtend(dst, slice.call(arguments, 1), false);
9643 }
9644
9645
9646 /**
9647 * @ngdoc function
9648 * @name angular.merge
9649 * @module ng
9650 * @kind function
9651 *
9652 * @description
9653 * Deeply extends the destination object `dst` by copying own enumerable properties from the `src` object(s)
9654 * to `dst`. You can specify multiple `src` objects. If you want to preserve original objects, you can do so
9655 * by passing an empty object as the target: `var object = angular.merge({}, object1, object2)`.
9656 *
9657 * Unlike {@link angular.extend extend()}, `merge()` recursively descends into object properties of source
9658 * objects, performing a deep copy.
9659 *
9660 * @param {Object} dst Destination object.
9661 * @param {...Object} src Source object(s).
9662 * @returns {Object} Reference to `dst`.
9663 */
9664 function merge(dst) {
9665   return baseExtend(dst, slice.call(arguments, 1), true);
9666 }
9667
9668
9669
9670 function toInt(str) {
9671   return parseInt(str, 10);
9672 }
9673
9674
9675 function inherit(parent, extra) {
9676   return extend(Object.create(parent), extra);
9677 }
9678
9679 /**
9680  * @ngdoc function
9681  * @name angular.noop
9682  * @module ng
9683  * @kind function
9684  *
9685  * @description
9686  * A function that performs no operations. This function can be useful when writing code in the
9687  * functional style.
9688    ```js
9689      function foo(callback) {
9690        var result = calculateResult();
9691        (callback || angular.noop)(result);
9692      }
9693    ```
9694  */
9695 function noop() {}
9696 noop.$inject = [];
9697
9698
9699 /**
9700  * @ngdoc function
9701  * @name angular.identity
9702  * @module ng
9703  * @kind function
9704  *
9705  * @description
9706  * A function that returns its first argument. This function is useful when writing code in the
9707  * functional style.
9708  *
9709    ```js
9710      function transformer(transformationFn, value) {
9711        return (transformationFn || angular.identity)(value);
9712      };
9713    ```
9714   * @param {*} value to be returned.
9715   * @returns {*} the value passed in.
9716  */
9717 function identity($) {return $;}
9718 identity.$inject = [];
9719
9720
9721 function valueFn(value) {return function() {return value;};}
9722
9723 function hasCustomToString(obj) {
9724   return isFunction(obj.toString) && obj.toString !== toString;
9725 }
9726
9727
9728 /**
9729  * @ngdoc function
9730  * @name angular.isUndefined
9731  * @module ng
9732  * @kind function
9733  *
9734  * @description
9735  * Determines if a reference is undefined.
9736  *
9737  * @param {*} value Reference to check.
9738  * @returns {boolean} True if `value` is undefined.
9739  */
9740 function isUndefined(value) {return typeof value === 'undefined';}
9741
9742
9743 /**
9744  * @ngdoc function
9745  * @name angular.isDefined
9746  * @module ng
9747  * @kind function
9748  *
9749  * @description
9750  * Determines if a reference is defined.
9751  *
9752  * @param {*} value Reference to check.
9753  * @returns {boolean} True if `value` is defined.
9754  */
9755 function isDefined(value) {return typeof value !== 'undefined';}
9756
9757
9758 /**
9759  * @ngdoc function
9760  * @name angular.isObject
9761  * @module ng
9762  * @kind function
9763  *
9764  * @description
9765  * Determines if a reference is an `Object`. Unlike `typeof` in JavaScript, `null`s are not
9766  * considered to be objects. Note that JavaScript arrays are objects.
9767  *
9768  * @param {*} value Reference to check.
9769  * @returns {boolean} True if `value` is an `Object` but not `null`.
9770  */
9771 function isObject(value) {
9772   // http://jsperf.com/isobject4
9773   return value !== null && typeof value === 'object';
9774 }
9775
9776
9777 /**
9778  * Determine if a value is an object with a null prototype
9779  *
9780  * @returns {boolean} True if `value` is an `Object` with a null prototype
9781  */
9782 function isBlankObject(value) {
9783   return value !== null && typeof value === 'object' && !getPrototypeOf(value);
9784 }
9785
9786
9787 /**
9788  * @ngdoc function
9789  * @name angular.isString
9790  * @module ng
9791  * @kind function
9792  *
9793  * @description
9794  * Determines if a reference is a `String`.
9795  *
9796  * @param {*} value Reference to check.
9797  * @returns {boolean} True if `value` is a `String`.
9798  */
9799 function isString(value) {return typeof value === 'string';}
9800
9801
9802 /**
9803  * @ngdoc function
9804  * @name angular.isNumber
9805  * @module ng
9806  * @kind function
9807  *
9808  * @description
9809  * Determines if a reference is a `Number`.
9810  *
9811  * This includes the "special" numbers `NaN`, `+Infinity` and `-Infinity`.
9812  *
9813  * If you wish to exclude these then you can use the native
9814  * [`isFinite'](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/isFinite)
9815  * method.
9816  *
9817  * @param {*} value Reference to check.
9818  * @returns {boolean} True if `value` is a `Number`.
9819  */
9820 function isNumber(value) {return typeof value === 'number';}
9821
9822
9823 /**
9824  * @ngdoc function
9825  * @name angular.isDate
9826  * @module ng
9827  * @kind function
9828  *
9829  * @description
9830  * Determines if a value is a date.
9831  *
9832  * @param {*} value Reference to check.
9833  * @returns {boolean} True if `value` is a `Date`.
9834  */
9835 function isDate(value) {
9836   return toString.call(value) === '[object Date]';
9837 }
9838
9839
9840 /**
9841  * @ngdoc function
9842  * @name angular.isArray
9843  * @module ng
9844  * @kind function
9845  *
9846  * @description
9847  * Determines if a reference is an `Array`.
9848  *
9849  * @param {*} value Reference to check.
9850  * @returns {boolean} True if `value` is an `Array`.
9851  */
9852 var isArray = Array.isArray;
9853
9854 /**
9855  * @ngdoc function
9856  * @name angular.isFunction
9857  * @module ng
9858  * @kind function
9859  *
9860  * @description
9861  * Determines if a reference is a `Function`.
9862  *
9863  * @param {*} value Reference to check.
9864  * @returns {boolean} True if `value` is a `Function`.
9865  */
9866 function isFunction(value) {return typeof value === 'function';}
9867
9868
9869 /**
9870  * Determines if a value is a regular expression object.
9871  *
9872  * @private
9873  * @param {*} value Reference to check.
9874  * @returns {boolean} True if `value` is a `RegExp`.
9875  */
9876 function isRegExp(value) {
9877   return toString.call(value) === '[object RegExp]';
9878 }
9879
9880
9881 /**
9882  * Checks if `obj` is a window object.
9883  *
9884  * @private
9885  * @param {*} obj Object to check
9886  * @returns {boolean} True if `obj` is a window obj.
9887  */
9888 function isWindow(obj) {
9889   return obj && obj.window === obj;
9890 }
9891
9892
9893 function isScope(obj) {
9894   return obj && obj.$evalAsync && obj.$watch;
9895 }
9896
9897
9898 function isFile(obj) {
9899   return toString.call(obj) === '[object File]';
9900 }
9901
9902
9903 function isFormData(obj) {
9904   return toString.call(obj) === '[object FormData]';
9905 }
9906
9907
9908 function isBlob(obj) {
9909   return toString.call(obj) === '[object Blob]';
9910 }
9911
9912
9913 function isBoolean(value) {
9914   return typeof value === 'boolean';
9915 }
9916
9917
9918 function isPromiseLike(obj) {
9919   return obj && isFunction(obj.then);
9920 }
9921
9922
9923 var TYPED_ARRAY_REGEXP = /^\[object (?:Uint8|Uint8Clamped|Uint16|Uint32|Int8|Int16|Int32|Float32|Float64)Array\]$/;
9924 function isTypedArray(value) {
9925   return value && isNumber(value.length) && TYPED_ARRAY_REGEXP.test(toString.call(value));
9926 }
9927
9928 function isArrayBuffer(obj) {
9929   return toString.call(obj) === '[object ArrayBuffer]';
9930 }
9931
9932
9933 var trim = function(value) {
9934   return isString(value) ? value.trim() : value;
9935 };
9936
9937 // Copied from:
9938 // http://docs.closure-library.googlecode.com/git/local_closure_goog_string_string.js.source.html#line1021
9939 // Prereq: s is a string.
9940 var escapeForRegexp = function(s) {
9941   return s.replace(/([-()\[\]{}+?*.$\^|,:#<!\\])/g, '\\$1').
9942            replace(/\x08/g, '\\x08');
9943 };
9944
9945
9946 /**
9947  * @ngdoc function
9948  * @name angular.isElement
9949  * @module ng
9950  * @kind function
9951  *
9952  * @description
9953  * Determines if a reference is a DOM element (or wrapped jQuery element).
9954  *
9955  * @param {*} value Reference to check.
9956  * @returns {boolean} True if `value` is a DOM element (or wrapped jQuery element).
9957  */
9958 function isElement(node) {
9959   return !!(node &&
9960     (node.nodeName  // we are a direct element
9961     || (node.prop && node.attr && node.find)));  // we have an on and find method part of jQuery API
9962 }
9963
9964 /**
9965  * @param str 'key1,key2,...'
9966  * @returns {object} in the form of {key1:true, key2:true, ...}
9967  */
9968 function makeMap(str) {
9969   var obj = {}, items = str.split(','), i;
9970   for (i = 0; i < items.length; i++) {
9971     obj[items[i]] = true;
9972   }
9973   return obj;
9974 }
9975
9976
9977 function nodeName_(element) {
9978   return lowercase(element.nodeName || (element[0] && element[0].nodeName));
9979 }
9980
9981 function includes(array, obj) {
9982   return Array.prototype.indexOf.call(array, obj) != -1;
9983 }
9984
9985 function arrayRemove(array, value) {
9986   var index = array.indexOf(value);
9987   if (index >= 0) {
9988     array.splice(index, 1);
9989   }
9990   return index;
9991 }
9992
9993 /**
9994  * @ngdoc function
9995  * @name angular.copy
9996  * @module ng
9997  * @kind function
9998  *
9999  * @description
10000  * Creates a deep copy of `source`, which should be an object or an array.
10001  *
10002  * * If no destination is supplied, a copy of the object or array is created.
10003  * * If a destination is provided, all of its elements (for arrays) or properties (for objects)
10004  *   are deleted and then all elements/properties from the source are copied to it.
10005  * * If `source` is not an object or array (inc. `null` and `undefined`), `source` is returned.
10006  * * If `source` is identical to 'destination' an exception will be thrown.
10007  *
10008  * @param {*} source The source that will be used to make a copy.
10009  *                   Can be any type, including primitives, `null`, and `undefined`.
10010  * @param {(Object|Array)=} destination Destination into which the source is copied. If
10011  *     provided, must be of the same type as `source`.
10012  * @returns {*} The copy or updated `destination`, if `destination` was specified.
10013  *
10014  * @example
10015  <example module="copyExample">
10016  <file name="index.html">
10017  <div ng-controller="ExampleController">
10018  <form novalidate class="simple-form">
10019  Name: <input type="text" ng-model="user.name" /><br />
10020  E-mail: <input type="email" ng-model="user.email" /><br />
10021  Gender: <input type="radio" ng-model="user.gender" value="male" />male
10022  <input type="radio" ng-model="user.gender" value="female" />female<br />
10023  <button ng-click="reset()">RESET</button>
10024  <button ng-click="update(user)">SAVE</button>
10025  </form>
10026  <pre>form = {{user | json}}</pre>
10027  <pre>master = {{master | json}}</pre>
10028  </div>
10029
10030  <script>
10031   angular.module('copyExample', [])
10032     .controller('ExampleController', ['$scope', function($scope) {
10033       $scope.master= {};
10034
10035       $scope.update = function(user) {
10036         // Example with 1 argument
10037         $scope.master= angular.copy(user);
10038       };
10039
10040       $scope.reset = function() {
10041         // Example with 2 arguments
10042         angular.copy($scope.master, $scope.user);
10043       };
10044
10045       $scope.reset();
10046     }]);
10047  </script>
10048  </file>
10049  </example>
10050  */
10051 function copy(source, destination) {
10052   var stackSource = [];
10053   var stackDest = [];
10054
10055   if (destination) {
10056     if (isTypedArray(destination) || isArrayBuffer(destination)) {
10057       throw ngMinErr('cpta', "Can't copy! TypedArray destination cannot be mutated.");
10058     }
10059     if (source === destination) {
10060       throw ngMinErr('cpi', "Can't copy! Source and destination are identical.");
10061     }
10062
10063     // Empty the destination object
10064     if (isArray(destination)) {
10065       destination.length = 0;
10066     } else {
10067       forEach(destination, function(value, key) {
10068         if (key !== '$$hashKey') {
10069           delete destination[key];
10070         }
10071       });
10072     }
10073
10074     stackSource.push(source);
10075     stackDest.push(destination);
10076     return copyRecurse(source, destination);
10077   }
10078
10079   return copyElement(source);
10080
10081   function copyRecurse(source, destination) {
10082     var h = destination.$$hashKey;
10083     var result, key;
10084     if (isArray(source)) {
10085       for (var i = 0, ii = source.length; i < ii; i++) {
10086         destination.push(copyElement(source[i]));
10087       }
10088     } else if (isBlankObject(source)) {
10089       // createMap() fast path --- Safe to avoid hasOwnProperty check because prototype chain is empty
10090       for (key in source) {
10091         destination[key] = copyElement(source[key]);
10092       }
10093     } else if (source && typeof source.hasOwnProperty === 'function') {
10094       // Slow path, which must rely on hasOwnProperty
10095       for (key in source) {
10096         if (source.hasOwnProperty(key)) {
10097           destination[key] = copyElement(source[key]);
10098         }
10099       }
10100     } else {
10101       // Slowest path --- hasOwnProperty can't be called as a method
10102       for (key in source) {
10103         if (hasOwnProperty.call(source, key)) {
10104           destination[key] = copyElement(source[key]);
10105         }
10106       }
10107     }
10108     setHashKey(destination, h);
10109     return destination;
10110   }
10111
10112   function copyElement(source) {
10113     // Simple values
10114     if (!isObject(source)) {
10115       return source;
10116     }
10117
10118     // Already copied values
10119     var index = stackSource.indexOf(source);
10120     if (index !== -1) {
10121       return stackDest[index];
10122     }
10123
10124     if (isWindow(source) || isScope(source)) {
10125       throw ngMinErr('cpws',
10126         "Can't copy! Making copies of Window or Scope instances is not supported.");
10127     }
10128
10129     var needsRecurse = false;
10130     var destination = copyType(source);
10131
10132     if (destination === undefined) {
10133       destination = isArray(source) ? [] : Object.create(getPrototypeOf(source));
10134       needsRecurse = true;
10135     }
10136
10137     stackSource.push(source);
10138     stackDest.push(destination);
10139
10140     return needsRecurse
10141       ? copyRecurse(source, destination)
10142       : destination;
10143   }
10144
10145   function copyType(source) {
10146     switch (toString.call(source)) {
10147       case '[object Int8Array]':
10148       case '[object Int16Array]':
10149       case '[object Int32Array]':
10150       case '[object Float32Array]':
10151       case '[object Float64Array]':
10152       case '[object Uint8Array]':
10153       case '[object Uint8ClampedArray]':
10154       case '[object Uint16Array]':
10155       case '[object Uint32Array]':
10156         return new source.constructor(copyElement(source.buffer));
10157
10158       case '[object ArrayBuffer]':
10159         //Support: IE10
10160         if (!source.slice) {
10161           var copied = new ArrayBuffer(source.byteLength);
10162           new Uint8Array(copied).set(new Uint8Array(source));
10163           return copied;
10164         }
10165         return source.slice(0);
10166
10167       case '[object Boolean]':
10168       case '[object Number]':
10169       case '[object String]':
10170       case '[object Date]':
10171         return new source.constructor(source.valueOf());
10172
10173       case '[object RegExp]':
10174         var re = new RegExp(source.source, source.toString().match(/[^\/]*$/)[0]);
10175         re.lastIndex = source.lastIndex;
10176         return re;
10177     }
10178
10179     if (isFunction(source.cloneNode)) {
10180       return source.cloneNode(true);
10181     }
10182   }
10183 }
10184
10185 /**
10186  * Creates a shallow copy of an object, an array or a primitive.
10187  *
10188  * Assumes that there are no proto properties for objects.
10189  */
10190 function shallowCopy(src, dst) {
10191   if (isArray(src)) {
10192     dst = dst || [];
10193
10194     for (var i = 0, ii = src.length; i < ii; i++) {
10195       dst[i] = src[i];
10196     }
10197   } else if (isObject(src)) {
10198     dst = dst || {};
10199
10200     for (var key in src) {
10201       if (!(key.charAt(0) === '$' && key.charAt(1) === '$')) {
10202         dst[key] = src[key];
10203       }
10204     }
10205   }
10206
10207   return dst || src;
10208 }
10209
10210
10211 /**
10212  * @ngdoc function
10213  * @name angular.equals
10214  * @module ng
10215  * @kind function
10216  *
10217  * @description
10218  * Determines if two objects or two values are equivalent. Supports value types, regular
10219  * expressions, arrays and objects.
10220  *
10221  * Two objects or values are considered equivalent if at least one of the following is true:
10222  *
10223  * * Both objects or values pass `===` comparison.
10224  * * Both objects or values are of the same type and all of their properties are equal by
10225  *   comparing them with `angular.equals`.
10226  * * Both values are NaN. (In JavaScript, NaN == NaN => false. But we consider two NaN as equal)
10227  * * Both values represent the same regular expression (In JavaScript,
10228  *   /abc/ == /abc/ => false. But we consider two regular expressions as equal when their textual
10229  *   representation matches).
10230  *
10231  * During a property comparison, properties of `function` type and properties with names
10232  * that begin with `$` are ignored.
10233  *
10234  * Scope and DOMWindow objects are being compared only by identify (`===`).
10235  *
10236  * @param {*} o1 Object or value to compare.
10237  * @param {*} o2 Object or value to compare.
10238  * @returns {boolean} True if arguments are equal.
10239  */
10240 function equals(o1, o2) {
10241   if (o1 === o2) return true;
10242   if (o1 === null || o2 === null) return false;
10243   if (o1 !== o1 && o2 !== o2) return true; // NaN === NaN
10244   var t1 = typeof o1, t2 = typeof o2, length, key, keySet;
10245   if (t1 == t2 && t1 == 'object') {
10246     if (isArray(o1)) {
10247       if (!isArray(o2)) return false;
10248       if ((length = o1.length) == o2.length) {
10249         for (key = 0; key < length; key++) {
10250           if (!equals(o1[key], o2[key])) return false;
10251         }
10252         return true;
10253       }
10254     } else if (isDate(o1)) {
10255       if (!isDate(o2)) return false;
10256       return equals(o1.getTime(), o2.getTime());
10257     } else if (isRegExp(o1)) {
10258       if (!isRegExp(o2)) return false;
10259       return o1.toString() == o2.toString();
10260     } else {
10261       if (isScope(o1) || isScope(o2) || isWindow(o1) || isWindow(o2) ||
10262         isArray(o2) || isDate(o2) || isRegExp(o2)) return false;
10263       keySet = createMap();
10264       for (key in o1) {
10265         if (key.charAt(0) === '$' || isFunction(o1[key])) continue;
10266         if (!equals(o1[key], o2[key])) return false;
10267         keySet[key] = true;
10268       }
10269       for (key in o2) {
10270         if (!(key in keySet) &&
10271             key.charAt(0) !== '$' &&
10272             isDefined(o2[key]) &&
10273             !isFunction(o2[key])) return false;
10274       }
10275       return true;
10276     }
10277   }
10278   return false;
10279 }
10280
10281 var csp = function() {
10282   if (!isDefined(csp.rules)) {
10283
10284
10285     var ngCspElement = (document.querySelector('[ng-csp]') ||
10286                     document.querySelector('[data-ng-csp]'));
10287
10288     if (ngCspElement) {
10289       var ngCspAttribute = ngCspElement.getAttribute('ng-csp') ||
10290                     ngCspElement.getAttribute('data-ng-csp');
10291       csp.rules = {
10292         noUnsafeEval: !ngCspAttribute || (ngCspAttribute.indexOf('no-unsafe-eval') !== -1),
10293         noInlineStyle: !ngCspAttribute || (ngCspAttribute.indexOf('no-inline-style') !== -1)
10294       };
10295     } else {
10296       csp.rules = {
10297         noUnsafeEval: noUnsafeEval(),
10298         noInlineStyle: false
10299       };
10300     }
10301   }
10302
10303   return csp.rules;
10304
10305   function noUnsafeEval() {
10306     try {
10307       /* jshint -W031, -W054 */
10308       new Function('');
10309       /* jshint +W031, +W054 */
10310       return false;
10311     } catch (e) {
10312       return true;
10313     }
10314   }
10315 };
10316
10317 /**
10318  * @ngdoc directive
10319  * @module ng
10320  * @name ngJq
10321  *
10322  * @element ANY
10323  * @param {string=} ngJq the name of the library available under `window`
10324  * to be used for angular.element
10325  * @description
10326  * Use this directive to force the angular.element library.  This should be
10327  * used to force either jqLite by leaving ng-jq blank or setting the name of
10328  * the jquery variable under window (eg. jQuery).
10329  *
10330  * Since angular looks for this directive when it is loaded (doesn't wait for the
10331  * DOMContentLoaded event), it must be placed on an element that comes before the script
10332  * which loads angular. Also, only the first instance of `ng-jq` will be used and all
10333  * others ignored.
10334  *
10335  * @example
10336  * This example shows how to force jqLite using the `ngJq` directive to the `html` tag.
10337  ```html
10338  <!doctype html>
10339  <html ng-app ng-jq>
10340  ...
10341  ...
10342  </html>
10343  ```
10344  * @example
10345  * This example shows how to use a jQuery based library of a different name.
10346  * The library name must be available at the top most 'window'.
10347  ```html
10348  <!doctype html>
10349  <html ng-app ng-jq="jQueryLib">
10350  ...
10351  ...
10352  </html>
10353  ```
10354  */
10355 var jq = function() {
10356   if (isDefined(jq.name_)) return jq.name_;
10357   var el;
10358   var i, ii = ngAttrPrefixes.length, prefix, name;
10359   for (i = 0; i < ii; ++i) {
10360     prefix = ngAttrPrefixes[i];
10361     if (el = document.querySelector('[' + prefix.replace(':', '\\:') + 'jq]')) {
10362       name = el.getAttribute(prefix + 'jq');
10363       break;
10364     }
10365   }
10366
10367   return (jq.name_ = name);
10368 };
10369
10370 function concat(array1, array2, index) {
10371   return array1.concat(slice.call(array2, index));
10372 }
10373
10374 function sliceArgs(args, startIndex) {
10375   return slice.call(args, startIndex || 0);
10376 }
10377
10378
10379 /* jshint -W101 */
10380 /**
10381  * @ngdoc function
10382  * @name angular.bind
10383  * @module ng
10384  * @kind function
10385  *
10386  * @description
10387  * Returns a function which calls function `fn` bound to `self` (`self` becomes the `this` for
10388  * `fn`). You can supply optional `args` that are prebound to the function. This feature is also
10389  * known as [partial application](http://en.wikipedia.org/wiki/Partial_application), as
10390  * distinguished from [function currying](http://en.wikipedia.org/wiki/Currying#Contrast_with_partial_function_application).
10391  *
10392  * @param {Object} self Context which `fn` should be evaluated in.
10393  * @param {function()} fn Function to be bound.
10394  * @param {...*} args Optional arguments to be prebound to the `fn` function call.
10395  * @returns {function()} Function that wraps the `fn` with all the specified bindings.
10396  */
10397 /* jshint +W101 */
10398 function bind(self, fn) {
10399   var curryArgs = arguments.length > 2 ? sliceArgs(arguments, 2) : [];
10400   if (isFunction(fn) && !(fn instanceof RegExp)) {
10401     return curryArgs.length
10402       ? function() {
10403           return arguments.length
10404             ? fn.apply(self, concat(curryArgs, arguments, 0))
10405             : fn.apply(self, curryArgs);
10406         }
10407       : function() {
10408           return arguments.length
10409             ? fn.apply(self, arguments)
10410             : fn.call(self);
10411         };
10412   } else {
10413     // in IE, native methods are not functions so they cannot be bound (note: they don't need to be)
10414     return fn;
10415   }
10416 }
10417
10418
10419 function toJsonReplacer(key, value) {
10420   var val = value;
10421
10422   if (typeof key === 'string' && key.charAt(0) === '$' && key.charAt(1) === '$') {
10423     val = undefined;
10424   } else if (isWindow(value)) {
10425     val = '$WINDOW';
10426   } else if (value &&  document === value) {
10427     val = '$DOCUMENT';
10428   } else if (isScope(value)) {
10429     val = '$SCOPE';
10430   }
10431
10432   return val;
10433 }
10434
10435
10436 /**
10437  * @ngdoc function
10438  * @name angular.toJson
10439  * @module ng
10440  * @kind function
10441  *
10442  * @description
10443  * Serializes input into a JSON-formatted string. Properties with leading $$ characters will be
10444  * stripped since angular uses this notation internally.
10445  *
10446  * @param {Object|Array|Date|string|number} obj Input to be serialized into JSON.
10447  * @param {boolean|number} [pretty=2] If set to true, the JSON output will contain newlines and whitespace.
10448  *    If set to an integer, the JSON output will contain that many spaces per indentation.
10449  * @returns {string|undefined} JSON-ified string representing `obj`.
10450  */
10451 function toJson(obj, pretty) {
10452   if (isUndefined(obj)) return undefined;
10453   if (!isNumber(pretty)) {
10454     pretty = pretty ? 2 : null;
10455   }
10456   return JSON.stringify(obj, toJsonReplacer, pretty);
10457 }
10458
10459
10460 /**
10461  * @ngdoc function
10462  * @name angular.fromJson
10463  * @module ng
10464  * @kind function
10465  *
10466  * @description
10467  * Deserializes a JSON string.
10468  *
10469  * @param {string} json JSON string to deserialize.
10470  * @returns {Object|Array|string|number} Deserialized JSON string.
10471  */
10472 function fromJson(json) {
10473   return isString(json)
10474       ? JSON.parse(json)
10475       : json;
10476 }
10477
10478
10479 var ALL_COLONS = /:/g;
10480 function timezoneToOffset(timezone, fallback) {
10481   // IE/Edge do not "understand" colon (`:`) in timezone
10482   timezone = timezone.replace(ALL_COLONS, '');
10483   var requestedTimezoneOffset = Date.parse('Jan 01, 1970 00:00:00 ' + timezone) / 60000;
10484   return isNaN(requestedTimezoneOffset) ? fallback : requestedTimezoneOffset;
10485 }
10486
10487
10488 function addDateMinutes(date, minutes) {
10489   date = new Date(date.getTime());
10490   date.setMinutes(date.getMinutes() + minutes);
10491   return date;
10492 }
10493
10494
10495 function convertTimezoneToLocal(date, timezone, reverse) {
10496   reverse = reverse ? -1 : 1;
10497   var dateTimezoneOffset = date.getTimezoneOffset();
10498   var timezoneOffset = timezoneToOffset(timezone, dateTimezoneOffset);
10499   return addDateMinutes(date, reverse * (timezoneOffset - dateTimezoneOffset));
10500 }
10501
10502
10503 /**
10504  * @returns {string} Returns the string representation of the element.
10505  */
10506 function startingTag(element) {
10507   element = jqLite(element).clone();
10508   try {
10509     // turns out IE does not let you set .html() on elements which
10510     // are not allowed to have children. So we just ignore it.
10511     element.empty();
10512   } catch (e) {}
10513   var elemHtml = jqLite('<div>').append(element).html();
10514   try {
10515     return element[0].nodeType === NODE_TYPE_TEXT ? lowercase(elemHtml) :
10516         elemHtml.
10517           match(/^(<[^>]+>)/)[1].
10518           replace(/^<([\w\-]+)/, function(match, nodeName) {return '<' + lowercase(nodeName);});
10519   } catch (e) {
10520     return lowercase(elemHtml);
10521   }
10522
10523 }
10524
10525
10526 /////////////////////////////////////////////////
10527
10528 /**
10529  * Tries to decode the URI component without throwing an exception.
10530  *
10531  * @private
10532  * @param str value potential URI component to check.
10533  * @returns {boolean} True if `value` can be decoded
10534  * with the decodeURIComponent function.
10535  */
10536 function tryDecodeURIComponent(value) {
10537   try {
10538     return decodeURIComponent(value);
10539   } catch (e) {
10540     // Ignore any invalid uri component
10541   }
10542 }
10543
10544
10545 /**
10546  * Parses an escaped url query string into key-value pairs.
10547  * @returns {Object.<string,boolean|Array>}
10548  */
10549 function parseKeyValue(/**string*/keyValue) {
10550   var obj = {};
10551   forEach((keyValue || "").split('&'), function(keyValue) {
10552     var splitPoint, key, val;
10553     if (keyValue) {
10554       key = keyValue = keyValue.replace(/\+/g,'%20');
10555       splitPoint = keyValue.indexOf('=');
10556       if (splitPoint !== -1) {
10557         key = keyValue.substring(0, splitPoint);
10558         val = keyValue.substring(splitPoint + 1);
10559       }
10560       key = tryDecodeURIComponent(key);
10561       if (isDefined(key)) {
10562         val = isDefined(val) ? tryDecodeURIComponent(val) : true;
10563         if (!hasOwnProperty.call(obj, key)) {
10564           obj[key] = val;
10565         } else if (isArray(obj[key])) {
10566           obj[key].push(val);
10567         } else {
10568           obj[key] = [obj[key],val];
10569         }
10570       }
10571     }
10572   });
10573   return obj;
10574 }
10575
10576 function toKeyValue(obj) {
10577   var parts = [];
10578   forEach(obj, function(value, key) {
10579     if (isArray(value)) {
10580       forEach(value, function(arrayValue) {
10581         parts.push(encodeUriQuery(key, true) +
10582                    (arrayValue === true ? '' : '=' + encodeUriQuery(arrayValue, true)));
10583       });
10584     } else {
10585     parts.push(encodeUriQuery(key, true) +
10586                (value === true ? '' : '=' + encodeUriQuery(value, true)));
10587     }
10588   });
10589   return parts.length ? parts.join('&') : '';
10590 }
10591
10592
10593 /**
10594  * We need our custom method because encodeURIComponent is too aggressive and doesn't follow
10595  * http://www.ietf.org/rfc/rfc3986.txt with regards to the character set (pchar) allowed in path
10596  * segments:
10597  *    segment       = *pchar
10598  *    pchar         = unreserved / pct-encoded / sub-delims / ":" / "@"
10599  *    pct-encoded   = "%" HEXDIG HEXDIG
10600  *    unreserved    = ALPHA / DIGIT / "-" / "." / "_" / "~"
10601  *    sub-delims    = "!" / "$" / "&" / "'" / "(" / ")"
10602  *                     / "*" / "+" / "," / ";" / "="
10603  */
10604 function encodeUriSegment(val) {
10605   return encodeUriQuery(val, true).
10606              replace(/%26/gi, '&').
10607              replace(/%3D/gi, '=').
10608              replace(/%2B/gi, '+');
10609 }
10610
10611
10612 /**
10613  * This method is intended for encoding *key* or *value* parts of query component. We need a custom
10614  * method because encodeURIComponent is too aggressive and encodes stuff that doesn't have to be
10615  * encoded per http://tools.ietf.org/html/rfc3986:
10616  *    query       = *( pchar / "/" / "?" )
10617  *    pchar         = unreserved / pct-encoded / sub-delims / ":" / "@"
10618  *    unreserved    = ALPHA / DIGIT / "-" / "." / "_" / "~"
10619  *    pct-encoded   = "%" HEXDIG HEXDIG
10620  *    sub-delims    = "!" / "$" / "&" / "'" / "(" / ")"
10621  *                     / "*" / "+" / "," / ";" / "="
10622  */
10623 function encodeUriQuery(val, pctEncodeSpaces) {
10624   return encodeURIComponent(val).
10625              replace(/%40/gi, '@').
10626              replace(/%3A/gi, ':').
10627              replace(/%24/g, '$').
10628              replace(/%2C/gi, ',').
10629              replace(/%3B/gi, ';').
10630              replace(/%20/g, (pctEncodeSpaces ? '%20' : '+'));
10631 }
10632
10633 var ngAttrPrefixes = ['ng-', 'data-ng-', 'ng:', 'x-ng-'];
10634
10635 function getNgAttribute(element, ngAttr) {
10636   var attr, i, ii = ngAttrPrefixes.length;
10637   for (i = 0; i < ii; ++i) {
10638     attr = ngAttrPrefixes[i] + ngAttr;
10639     if (isString(attr = element.getAttribute(attr))) {
10640       return attr;
10641     }
10642   }
10643   return null;
10644 }
10645
10646 /**
10647  * @ngdoc directive
10648  * @name ngApp
10649  * @module ng
10650  *
10651  * @element ANY
10652  * @param {angular.Module} ngApp an optional application
10653  *   {@link angular.module module} name to load.
10654  * @param {boolean=} ngStrictDi if this attribute is present on the app element, the injector will be
10655  *   created in "strict-di" mode. This means that the application will fail to invoke functions which
10656  *   do not use explicit function annotation (and are thus unsuitable for minification), as described
10657  *   in {@link guide/di the Dependency Injection guide}, and useful debugging info will assist in
10658  *   tracking down the root of these bugs.
10659  *
10660  * @description
10661  *
10662  * Use this directive to **auto-bootstrap** an AngularJS application. The `ngApp` directive
10663  * designates the **root element** of the application and is typically placed near the root element
10664  * of the page - e.g. on the `<body>` or `<html>` tags.
10665  *
10666  * Only one AngularJS application can be auto-bootstrapped per HTML document. The first `ngApp`
10667  * found in the document will be used to define the root element to auto-bootstrap as an
10668  * application. To run multiple applications in an HTML document you must manually bootstrap them using
10669  * {@link angular.bootstrap} instead. AngularJS applications cannot be nested within each other.
10670  *
10671  * You can specify an **AngularJS module** to be used as the root module for the application.  This
10672  * module will be loaded into the {@link auto.$injector} when the application is bootstrapped. It
10673  * should contain the application code needed or have dependencies on other modules that will
10674  * contain the code. See {@link angular.module} for more information.
10675  *
10676  * In the example below if the `ngApp` directive were not placed on the `html` element then the
10677  * document would not be compiled, the `AppController` would not be instantiated and the `{{ a+b }}`
10678  * would not be resolved to `3`.
10679  *
10680  * `ngApp` is the easiest, and most common way to bootstrap an application.
10681  *
10682  <example module="ngAppDemo">
10683    <file name="index.html">
10684    <div ng-controller="ngAppDemoController">
10685      I can add: {{a}} + {{b}} =  {{ a+b }}
10686    </div>
10687    </file>
10688    <file name="script.js">
10689    angular.module('ngAppDemo', []).controller('ngAppDemoController', function($scope) {
10690      $scope.a = 1;
10691      $scope.b = 2;
10692    });
10693    </file>
10694  </example>
10695  *
10696  * Using `ngStrictDi`, you would see something like this:
10697  *
10698  <example ng-app-included="true">
10699    <file name="index.html">
10700    <div ng-app="ngAppStrictDemo" ng-strict-di>
10701        <div ng-controller="GoodController1">
10702            I can add: {{a}} + {{b}} =  {{ a+b }}
10703
10704            <p>This renders because the controller does not fail to
10705               instantiate, by using explicit annotation style (see
10706               script.js for details)
10707            </p>
10708        </div>
10709
10710        <div ng-controller="GoodController2">
10711            Name: <input ng-model="name"><br />
10712            Hello, {{name}}!
10713
10714            <p>This renders because the controller does not fail to
10715               instantiate, by using explicit annotation style
10716               (see script.js for details)
10717            </p>
10718        </div>
10719
10720        <div ng-controller="BadController">
10721            I can add: {{a}} + {{b}} =  {{ a+b }}
10722
10723            <p>The controller could not be instantiated, due to relying
10724               on automatic function annotations (which are disabled in
10725               strict mode). As such, the content of this section is not
10726               interpolated, and there should be an error in your web console.
10727            </p>
10728        </div>
10729    </div>
10730    </file>
10731    <file name="script.js">
10732    angular.module('ngAppStrictDemo', [])
10733      // BadController will fail to instantiate, due to relying on automatic function annotation,
10734      // rather than an explicit annotation
10735      .controller('BadController', function($scope) {
10736        $scope.a = 1;
10737        $scope.b = 2;
10738      })
10739      // Unlike BadController, GoodController1 and GoodController2 will not fail to be instantiated,
10740      // due to using explicit annotations using the array style and $inject property, respectively.
10741      .controller('GoodController1', ['$scope', function($scope) {
10742        $scope.a = 1;
10743        $scope.b = 2;
10744      }])
10745      .controller('GoodController2', GoodController2);
10746      function GoodController2($scope) {
10747        $scope.name = "World";
10748      }
10749      GoodController2.$inject = ['$scope'];
10750    </file>
10751    <file name="style.css">
10752    div[ng-controller] {
10753        margin-bottom: 1em;
10754        -webkit-border-radius: 4px;
10755        border-radius: 4px;
10756        border: 1px solid;
10757        padding: .5em;
10758    }
10759    div[ng-controller^=Good] {
10760        border-color: #d6e9c6;
10761        background-color: #dff0d8;
10762        color: #3c763d;
10763    }
10764    div[ng-controller^=Bad] {
10765        border-color: #ebccd1;
10766        background-color: #f2dede;
10767        color: #a94442;
10768        margin-bottom: 0;
10769    }
10770    </file>
10771  </example>
10772  */
10773 function angularInit(element, bootstrap) {
10774   var appElement,
10775       module,
10776       config = {};
10777
10778   // The element `element` has priority over any other element
10779   forEach(ngAttrPrefixes, function(prefix) {
10780     var name = prefix + 'app';
10781
10782     if (!appElement && element.hasAttribute && element.hasAttribute(name)) {
10783       appElement = element;
10784       module = element.getAttribute(name);
10785     }
10786   });
10787   forEach(ngAttrPrefixes, function(prefix) {
10788     var name = prefix + 'app';
10789     var candidate;
10790
10791     if (!appElement && (candidate = element.querySelector('[' + name.replace(':', '\\:') + ']'))) {
10792       appElement = candidate;
10793       module = candidate.getAttribute(name);
10794     }
10795   });
10796   if (appElement) {
10797     config.strictDi = getNgAttribute(appElement, "strict-di") !== null;
10798     bootstrap(appElement, module ? [module] : [], config);
10799   }
10800 }
10801
10802 /**
10803  * @ngdoc function
10804  * @name angular.bootstrap
10805  * @module ng
10806  * @description
10807  * Use this function to manually start up angular application.
10808  *
10809  * See: {@link guide/bootstrap Bootstrap}
10810  *
10811  * Note that Protractor based end-to-end tests cannot use this function to bootstrap manually.
10812  * They must use {@link ng.directive:ngApp ngApp}.
10813  *
10814  * Angular will detect if it has been loaded into the browser more than once and only allow the
10815  * first loaded script to be bootstrapped and will report a warning to the browser console for
10816  * each of the subsequent scripts. This prevents strange results in applications, where otherwise
10817  * multiple instances of Angular try to work on the DOM.
10818  *
10819  * ```html
10820  * <!doctype html>
10821  * <html>
10822  * <body>
10823  * <div ng-controller="WelcomeController">
10824  *   {{greeting}}
10825  * </div>
10826  *
10827  * <script src="angular.js"></script>
10828  * <script>
10829  *   var app = angular.module('demo', [])
10830  *   .controller('WelcomeController', function($scope) {
10831  *       $scope.greeting = 'Welcome!';
10832  *   });
10833  *   angular.bootstrap(document, ['demo']);
10834  * </script>
10835  * </body>
10836  * </html>
10837  * ```
10838  *
10839  * @param {DOMElement} element DOM element which is the root of angular application.
10840  * @param {Array<String|Function|Array>=} modules an array of modules to load into the application.
10841  *     Each item in the array should be the name of a predefined module or a (DI annotated)
10842  *     function that will be invoked by the injector as a `config` block.
10843  *     See: {@link angular.module modules}
10844  * @param {Object=} config an object for defining configuration options for the application. The
10845  *     following keys are supported:
10846  *
10847  * * `strictDi` - disable automatic function annotation for the application. This is meant to
10848  *   assist in finding bugs which break minified code. Defaults to `false`.
10849  *
10850  * @returns {auto.$injector} Returns the newly created injector for this app.
10851  */
10852 function bootstrap(element, modules, config) {
10853   if (!isObject(config)) config = {};
10854   var defaultConfig = {
10855     strictDi: false
10856   };
10857   config = extend(defaultConfig, config);
10858   var doBootstrap = function() {
10859     element = jqLite(element);
10860
10861     if (element.injector()) {
10862       var tag = (element[0] === document) ? 'document' : startingTag(element);
10863       //Encode angle brackets to prevent input from being sanitized to empty string #8683
10864       throw ngMinErr(
10865           'btstrpd',
10866           "App Already Bootstrapped with this Element '{0}'",
10867           tag.replace(/</,'&lt;').replace(/>/,'&gt;'));
10868     }
10869
10870     modules = modules || [];
10871     modules.unshift(['$provide', function($provide) {
10872       $provide.value('$rootElement', element);
10873     }]);
10874
10875     if (config.debugInfoEnabled) {
10876       // Pushing so that this overrides `debugInfoEnabled` setting defined in user's `modules`.
10877       modules.push(['$compileProvider', function($compileProvider) {
10878         $compileProvider.debugInfoEnabled(true);
10879       }]);
10880     }
10881
10882     modules.unshift('ng');
10883     var injector = createInjector(modules, config.strictDi);
10884     injector.invoke(['$rootScope', '$rootElement', '$compile', '$injector',
10885        function bootstrapApply(scope, element, compile, injector) {
10886         scope.$apply(function() {
10887           element.data('$injector', injector);
10888           compile(element)(scope);
10889         });
10890       }]
10891     );
10892     return injector;
10893   };
10894
10895   var NG_ENABLE_DEBUG_INFO = /^NG_ENABLE_DEBUG_INFO!/;
10896   var NG_DEFER_BOOTSTRAP = /^NG_DEFER_BOOTSTRAP!/;
10897
10898   if (window && NG_ENABLE_DEBUG_INFO.test(window.name)) {
10899     config.debugInfoEnabled = true;
10900     window.name = window.name.replace(NG_ENABLE_DEBUG_INFO, '');
10901   }
10902
10903   if (window && !NG_DEFER_BOOTSTRAP.test(window.name)) {
10904     return doBootstrap();
10905   }
10906
10907   window.name = window.name.replace(NG_DEFER_BOOTSTRAP, '');
10908   angular.resumeBootstrap = function(extraModules) {
10909     forEach(extraModules, function(module) {
10910       modules.push(module);
10911     });
10912     return doBootstrap();
10913   };
10914
10915   if (isFunction(angular.resumeDeferredBootstrap)) {
10916     angular.resumeDeferredBootstrap();
10917   }
10918 }
10919
10920 /**
10921  * @ngdoc function
10922  * @name angular.reloadWithDebugInfo
10923  * @module ng
10924  * @description
10925  * Use this function to reload the current application with debug information turned on.
10926  * This takes precedence over a call to `$compileProvider.debugInfoEnabled(false)`.
10927  *
10928  * See {@link ng.$compileProvider#debugInfoEnabled} for more.
10929  */
10930 function reloadWithDebugInfo() {
10931   window.name = 'NG_ENABLE_DEBUG_INFO!' + window.name;
10932   window.location.reload();
10933 }
10934
10935 /**
10936  * @name angular.getTestability
10937  * @module ng
10938  * @description
10939  * Get the testability service for the instance of Angular on the given
10940  * element.
10941  * @param {DOMElement} element DOM element which is the root of angular application.
10942  */
10943 function getTestability(rootElement) {
10944   var injector = angular.element(rootElement).injector();
10945   if (!injector) {
10946     throw ngMinErr('test',
10947       'no injector found for element argument to getTestability');
10948   }
10949   return injector.get('$$testability');
10950 }
10951
10952 var SNAKE_CASE_REGEXP = /[A-Z]/g;
10953 function snake_case(name, separator) {
10954   separator = separator || '_';
10955   return name.replace(SNAKE_CASE_REGEXP, function(letter, pos) {
10956     return (pos ? separator : '') + letter.toLowerCase();
10957   });
10958 }
10959
10960 var bindJQueryFired = false;
10961 function bindJQuery() {
10962   var originalCleanData;
10963
10964   if (bindJQueryFired) {
10965     return;
10966   }
10967
10968   // bind to jQuery if present;
10969   var jqName = jq();
10970   jQuery = isUndefined(jqName) ? window.jQuery :   // use jQuery (if present)
10971            !jqName             ? undefined     :   // use jqLite
10972                                  window[jqName];   // use jQuery specified by `ngJq`
10973
10974   // Use jQuery if it exists with proper functionality, otherwise default to us.
10975   // Angular 1.2+ requires jQuery 1.7+ for on()/off() support.
10976   // Angular 1.3+ technically requires at least jQuery 2.1+ but it may work with older
10977   // versions. It will not work for sure with jQuery <1.7, though.
10978   if (jQuery && jQuery.fn.on) {
10979     jqLite = jQuery;
10980     extend(jQuery.fn, {
10981       scope: JQLitePrototype.scope,
10982       isolateScope: JQLitePrototype.isolateScope,
10983       controller: JQLitePrototype.controller,
10984       injector: JQLitePrototype.injector,
10985       inheritedData: JQLitePrototype.inheritedData
10986     });
10987
10988     // All nodes removed from the DOM via various jQuery APIs like .remove()
10989     // are passed through jQuery.cleanData. Monkey-patch this method to fire
10990     // the $destroy event on all removed nodes.
10991     originalCleanData = jQuery.cleanData;
10992     jQuery.cleanData = function(elems) {
10993       var events;
10994       for (var i = 0, elem; (elem = elems[i]) != null; i++) {
10995         events = jQuery._data(elem, "events");
10996         if (events && events.$destroy) {
10997           jQuery(elem).triggerHandler('$destroy');
10998         }
10999       }
11000       originalCleanData(elems);
11001     };
11002   } else {
11003     jqLite = JQLite;
11004   }
11005
11006   angular.element = jqLite;
11007
11008   // Prevent double-proxying.
11009   bindJQueryFired = true;
11010 }
11011
11012 /**
11013  * throw error if the argument is falsy.
11014  */
11015 function assertArg(arg, name, reason) {
11016   if (!arg) {
11017     throw ngMinErr('areq', "Argument '{0}' is {1}", (name || '?'), (reason || "required"));
11018   }
11019   return arg;
11020 }
11021
11022 function assertArgFn(arg, name, acceptArrayAnnotation) {
11023   if (acceptArrayAnnotation && isArray(arg)) {
11024       arg = arg[arg.length - 1];
11025   }
11026
11027   assertArg(isFunction(arg), name, 'not a function, got ' +
11028       (arg && typeof arg === 'object' ? arg.constructor.name || 'Object' : typeof arg));
11029   return arg;
11030 }
11031
11032 /**
11033  * throw error if the name given is hasOwnProperty
11034  * @param  {String} name    the name to test
11035  * @param  {String} context the context in which the name is used, such as module or directive
11036  */
11037 function assertNotHasOwnProperty(name, context) {
11038   if (name === 'hasOwnProperty') {
11039     throw ngMinErr('badname', "hasOwnProperty is not a valid {0} name", context);
11040   }
11041 }
11042
11043 /**
11044  * Return the value accessible from the object by path. Any undefined traversals are ignored
11045  * @param {Object} obj starting object
11046  * @param {String} path path to traverse
11047  * @param {boolean} [bindFnToScope=true]
11048  * @returns {Object} value as accessible by path
11049  */
11050 //TODO(misko): this function needs to be removed
11051 function getter(obj, path, bindFnToScope) {
11052   if (!path) return obj;
11053   var keys = path.split('.');
11054   var key;
11055   var lastInstance = obj;
11056   var len = keys.length;
11057
11058   for (var i = 0; i < len; i++) {
11059     key = keys[i];
11060     if (obj) {
11061       obj = (lastInstance = obj)[key];
11062     }
11063   }
11064   if (!bindFnToScope && isFunction(obj)) {
11065     return bind(lastInstance, obj);
11066   }
11067   return obj;
11068 }
11069
11070 /**
11071  * Return the DOM siblings between the first and last node in the given array.
11072  * @param {Array} array like object
11073  * @returns {Array} the inputted object or a jqLite collection containing the nodes
11074  */
11075 function getBlockNodes(nodes) {
11076   // TODO(perf): update `nodes` instead of creating a new object?
11077   var node = nodes[0];
11078   var endNode = nodes[nodes.length - 1];
11079   var blockNodes;
11080
11081   for (var i = 1; node !== endNode && (node = node.nextSibling); i++) {
11082     if (blockNodes || nodes[i] !== node) {
11083       if (!blockNodes) {
11084         blockNodes = jqLite(slice.call(nodes, 0, i));
11085       }
11086       blockNodes.push(node);
11087     }
11088   }
11089
11090   return blockNodes || nodes;
11091 }
11092
11093
11094 /**
11095  * Creates a new object without a prototype. This object is useful for lookup without having to
11096  * guard against prototypically inherited properties via hasOwnProperty.
11097  *
11098  * Related micro-benchmarks:
11099  * - http://jsperf.com/object-create2
11100  * - http://jsperf.com/proto-map-lookup/2
11101  * - http://jsperf.com/for-in-vs-object-keys2
11102  *
11103  * @returns {Object}
11104  */
11105 function createMap() {
11106   return Object.create(null);
11107 }
11108
11109 var NODE_TYPE_ELEMENT = 1;
11110 var NODE_TYPE_ATTRIBUTE = 2;
11111 var NODE_TYPE_TEXT = 3;
11112 var NODE_TYPE_COMMENT = 8;
11113 var NODE_TYPE_DOCUMENT = 9;
11114 var NODE_TYPE_DOCUMENT_FRAGMENT = 11;
11115
11116 /**
11117  * @ngdoc type
11118  * @name angular.Module
11119  * @module ng
11120  * @description
11121  *
11122  * Interface for configuring angular {@link angular.module modules}.
11123  */
11124
11125 function setupModuleLoader(window) {
11126
11127   var $injectorMinErr = minErr('$injector');
11128   var ngMinErr = minErr('ng');
11129
11130   function ensure(obj, name, factory) {
11131     return obj[name] || (obj[name] = factory());
11132   }
11133
11134   var angular = ensure(window, 'angular', Object);
11135
11136   // We need to expose `angular.$$minErr` to modules such as `ngResource` that reference it during bootstrap
11137   angular.$$minErr = angular.$$minErr || minErr;
11138
11139   return ensure(angular, 'module', function() {
11140     /** @type {Object.<string, angular.Module>} */
11141     var modules = {};
11142
11143     /**
11144      * @ngdoc function
11145      * @name angular.module
11146      * @module ng
11147      * @description
11148      *
11149      * The `angular.module` is a global place for creating, registering and retrieving Angular
11150      * modules.
11151      * All modules (angular core or 3rd party) that should be available to an application must be
11152      * registered using this mechanism.
11153      *
11154      * Passing one argument retrieves an existing {@link angular.Module},
11155      * whereas passing more than one argument creates a new {@link angular.Module}
11156      *
11157      *
11158      * # Module
11159      *
11160      * A module is a collection of services, directives, controllers, filters, and configuration information.
11161      * `angular.module` is used to configure the {@link auto.$injector $injector}.
11162      *
11163      * ```js
11164      * // Create a new module
11165      * var myModule = angular.module('myModule', []);
11166      *
11167      * // register a new service
11168      * myModule.value('appName', 'MyCoolApp');
11169      *
11170      * // configure existing services inside initialization blocks.
11171      * myModule.config(['$locationProvider', function($locationProvider) {
11172      *   // Configure existing providers
11173      *   $locationProvider.hashPrefix('!');
11174      * }]);
11175      * ```
11176      *
11177      * Then you can create an injector and load your modules like this:
11178      *
11179      * ```js
11180      * var injector = angular.injector(['ng', 'myModule'])
11181      * ```
11182      *
11183      * However it's more likely that you'll just use
11184      * {@link ng.directive:ngApp ngApp} or
11185      * {@link angular.bootstrap} to simplify this process for you.
11186      *
11187      * @param {!string} name The name of the module to create or retrieve.
11188      * @param {!Array.<string>=} requires If specified then new module is being created. If
11189      *        unspecified then the module is being retrieved for further configuration.
11190      * @param {Function=} configFn Optional configuration function for the module. Same as
11191      *        {@link angular.Module#config Module#config()}.
11192      * @returns {angular.Module} new module with the {@link angular.Module} api.
11193      */
11194     return function module(name, requires, configFn) {
11195       var assertNotHasOwnProperty = function(name, context) {
11196         if (name === 'hasOwnProperty') {
11197           throw ngMinErr('badname', 'hasOwnProperty is not a valid {0} name', context);
11198         }
11199       };
11200
11201       assertNotHasOwnProperty(name, 'module');
11202       if (requires && modules.hasOwnProperty(name)) {
11203         modules[name] = null;
11204       }
11205       return ensure(modules, name, function() {
11206         if (!requires) {
11207           throw $injectorMinErr('nomod', "Module '{0}' is not available! You either misspelled " +
11208              "the module name or forgot to load it. If registering a module ensure that you " +
11209              "specify the dependencies as the second argument.", name);
11210         }
11211
11212         /** @type {!Array.<Array.<*>>} */
11213         var invokeQueue = [];
11214
11215         /** @type {!Array.<Function>} */
11216         var configBlocks = [];
11217
11218         /** @type {!Array.<Function>} */
11219         var runBlocks = [];
11220
11221         var config = invokeLater('$injector', 'invoke', 'push', configBlocks);
11222
11223         /** @type {angular.Module} */
11224         var moduleInstance = {
11225           // Private state
11226           _invokeQueue: invokeQueue,
11227           _configBlocks: configBlocks,
11228           _runBlocks: runBlocks,
11229
11230           /**
11231            * @ngdoc property
11232            * @name angular.Module#requires
11233            * @module ng
11234            *
11235            * @description
11236            * Holds the list of modules which the injector will load before the current module is
11237            * loaded.
11238            */
11239           requires: requires,
11240
11241           /**
11242            * @ngdoc property
11243            * @name angular.Module#name
11244            * @module ng
11245            *
11246            * @description
11247            * Name of the module.
11248            */
11249           name: name,
11250
11251
11252           /**
11253            * @ngdoc method
11254            * @name angular.Module#provider
11255            * @module ng
11256            * @param {string} name service name
11257            * @param {Function} providerType Construction function for creating new instance of the
11258            *                                service.
11259            * @description
11260            * See {@link auto.$provide#provider $provide.provider()}.
11261            */
11262           provider: invokeLaterAndSetModuleName('$provide', 'provider'),
11263
11264           /**
11265            * @ngdoc method
11266            * @name angular.Module#factory
11267            * @module ng
11268            * @param {string} name service name
11269            * @param {Function} providerFunction Function for creating new instance of the service.
11270            * @description
11271            * See {@link auto.$provide#factory $provide.factory()}.
11272            */
11273           factory: invokeLaterAndSetModuleName('$provide', 'factory'),
11274
11275           /**
11276            * @ngdoc method
11277            * @name angular.Module#service
11278            * @module ng
11279            * @param {string} name service name
11280            * @param {Function} constructor A constructor function that will be instantiated.
11281            * @description
11282            * See {@link auto.$provide#service $provide.service()}.
11283            */
11284           service: invokeLaterAndSetModuleName('$provide', 'service'),
11285
11286           /**
11287            * @ngdoc method
11288            * @name angular.Module#value
11289            * @module ng
11290            * @param {string} name service name
11291            * @param {*} object Service instance object.
11292            * @description
11293            * See {@link auto.$provide#value $provide.value()}.
11294            */
11295           value: invokeLater('$provide', 'value'),
11296
11297           /**
11298            * @ngdoc method
11299            * @name angular.Module#constant
11300            * @module ng
11301            * @param {string} name constant name
11302            * @param {*} object Constant value.
11303            * @description
11304            * Because the constants are fixed, they get applied before other provide methods.
11305            * See {@link auto.$provide#constant $provide.constant()}.
11306            */
11307           constant: invokeLater('$provide', 'constant', 'unshift'),
11308
11309            /**
11310            * @ngdoc method
11311            * @name angular.Module#decorator
11312            * @module ng
11313            * @param {string} The name of the service to decorate.
11314            * @param {Function} This function will be invoked when the service needs to be
11315            *                                    instantiated and should return the decorated service instance.
11316            * @description
11317            * See {@link auto.$provide#decorator $provide.decorator()}.
11318            */
11319           decorator: invokeLaterAndSetModuleName('$provide', 'decorator'),
11320
11321           /**
11322            * @ngdoc method
11323            * @name angular.Module#animation
11324            * @module ng
11325            * @param {string} name animation name
11326            * @param {Function} animationFactory Factory function for creating new instance of an
11327            *                                    animation.
11328            * @description
11329            *
11330            * **NOTE**: animations take effect only if the **ngAnimate** module is loaded.
11331            *
11332            *
11333            * Defines an animation hook that can be later used with
11334            * {@link $animate $animate} service and directives that use this service.
11335            *
11336            * ```js
11337            * module.animation('.animation-name', function($inject1, $inject2) {
11338            *   return {
11339            *     eventName : function(element, done) {
11340            *       //code to run the animation
11341            *       //once complete, then run done()
11342            *       return function cancellationFunction(element) {
11343            *         //code to cancel the animation
11344            *       }
11345            *     }
11346            *   }
11347            * })
11348            * ```
11349            *
11350            * See {@link ng.$animateProvider#register $animateProvider.register()} and
11351            * {@link ngAnimate ngAnimate module} for more information.
11352            */
11353           animation: invokeLaterAndSetModuleName('$animateProvider', 'register'),
11354
11355           /**
11356            * @ngdoc method
11357            * @name angular.Module#filter
11358            * @module ng
11359            * @param {string} name Filter name - this must be a valid angular expression identifier
11360            * @param {Function} filterFactory Factory function for creating new instance of filter.
11361            * @description
11362            * See {@link ng.$filterProvider#register $filterProvider.register()}.
11363            *
11364            * <div class="alert alert-warning">
11365            * **Note:** Filter names must be valid angular {@link expression} identifiers, such as `uppercase` or `orderBy`.
11366            * Names with special characters, such as hyphens and dots, are not allowed. If you wish to namespace
11367            * your filters, then you can use capitalization (`myappSubsectionFilterx`) or underscores
11368            * (`myapp_subsection_filterx`).
11369            * </div>
11370            */
11371           filter: invokeLaterAndSetModuleName('$filterProvider', 'register'),
11372
11373           /**
11374            * @ngdoc method
11375            * @name angular.Module#controller
11376            * @module ng
11377            * @param {string|Object} name Controller name, or an object map of controllers where the
11378            *    keys are the names and the values are the constructors.
11379            * @param {Function} constructor Controller constructor function.
11380            * @description
11381            * See {@link ng.$controllerProvider#register $controllerProvider.register()}.
11382            */
11383           controller: invokeLaterAndSetModuleName('$controllerProvider', 'register'),
11384
11385           /**
11386            * @ngdoc method
11387            * @name angular.Module#directive
11388            * @module ng
11389            * @param {string|Object} name Directive name, or an object map of directives where the
11390            *    keys are the names and the values are the factories.
11391            * @param {Function} directiveFactory Factory function for creating new instance of
11392            * directives.
11393            * @description
11394            * See {@link ng.$compileProvider#directive $compileProvider.directive()}.
11395            */
11396           directive: invokeLaterAndSetModuleName('$compileProvider', 'directive'),
11397
11398           /**
11399            * @ngdoc method
11400            * @name angular.Module#component
11401            * @module ng
11402            * @param {string} name Name of the component in camel-case (i.e. myComp which will match as my-comp)
11403            * @param {Object} options Component definition object (a simplified
11404            *    {@link ng.$compile#directive-definition-object directive definition object})
11405            *
11406            * @description
11407            * See {@link ng.$compileProvider#component $compileProvider.component()}.
11408            */
11409           component: invokeLaterAndSetModuleName('$compileProvider', 'component'),
11410
11411           /**
11412            * @ngdoc method
11413            * @name angular.Module#config
11414            * @module ng
11415            * @param {Function} configFn Execute this function on module load. Useful for service
11416            *    configuration.
11417            * @description
11418            * Use this method to register work which needs to be performed on module loading.
11419            * For more about how to configure services, see
11420            * {@link providers#provider-recipe Provider Recipe}.
11421            */
11422           config: config,
11423
11424           /**
11425            * @ngdoc method
11426            * @name angular.Module#run
11427            * @module ng
11428            * @param {Function} initializationFn Execute this function after injector creation.
11429            *    Useful for application initialization.
11430            * @description
11431            * Use this method to register work which should be performed when the injector is done
11432            * loading all modules.
11433            */
11434           run: function(block) {
11435             runBlocks.push(block);
11436             return this;
11437           }
11438         };
11439
11440         if (configFn) {
11441           config(configFn);
11442         }
11443
11444         return moduleInstance;
11445
11446         /**
11447          * @param {string} provider
11448          * @param {string} method
11449          * @param {String=} insertMethod
11450          * @returns {angular.Module}
11451          */
11452         function invokeLater(provider, method, insertMethod, queue) {
11453           if (!queue) queue = invokeQueue;
11454           return function() {
11455             queue[insertMethod || 'push']([provider, method, arguments]);
11456             return moduleInstance;
11457           };
11458         }
11459
11460         /**
11461          * @param {string} provider
11462          * @param {string} method
11463          * @returns {angular.Module}
11464          */
11465         function invokeLaterAndSetModuleName(provider, method) {
11466           return function(recipeName, factoryFunction) {
11467             if (factoryFunction && isFunction(factoryFunction)) factoryFunction.$$moduleName = name;
11468             invokeQueue.push([provider, method, arguments]);
11469             return moduleInstance;
11470           };
11471         }
11472       });
11473     };
11474   });
11475
11476 }
11477
11478 /* global: toDebugString: true */
11479
11480 function serializeObject(obj) {
11481   var seen = [];
11482
11483   return JSON.stringify(obj, function(key, val) {
11484     val = toJsonReplacer(key, val);
11485     if (isObject(val)) {
11486
11487       if (seen.indexOf(val) >= 0) return '...';
11488
11489       seen.push(val);
11490     }
11491     return val;
11492   });
11493 }
11494
11495 function toDebugString(obj) {
11496   if (typeof obj === 'function') {
11497     return obj.toString().replace(/ \{[\s\S]*$/, '');
11498   } else if (isUndefined(obj)) {
11499     return 'undefined';
11500   } else if (typeof obj !== 'string') {
11501     return serializeObject(obj);
11502   }
11503   return obj;
11504 }
11505
11506 /* global angularModule: true,
11507   version: true,
11508
11509   $CompileProvider,
11510
11511   htmlAnchorDirective,
11512   inputDirective,
11513   inputDirective,
11514   formDirective,
11515   scriptDirective,
11516   selectDirective,
11517   styleDirective,
11518   optionDirective,
11519   ngBindDirective,
11520   ngBindHtmlDirective,
11521   ngBindTemplateDirective,
11522   ngClassDirective,
11523   ngClassEvenDirective,
11524   ngClassOddDirective,
11525   ngCloakDirective,
11526   ngControllerDirective,
11527   ngFormDirective,
11528   ngHideDirective,
11529   ngIfDirective,
11530   ngIncludeDirective,
11531   ngIncludeFillContentDirective,
11532   ngInitDirective,
11533   ngNonBindableDirective,
11534   ngPluralizeDirective,
11535   ngRepeatDirective,
11536   ngShowDirective,
11537   ngStyleDirective,
11538   ngSwitchDirective,
11539   ngSwitchWhenDirective,
11540   ngSwitchDefaultDirective,
11541   ngOptionsDirective,
11542   ngTranscludeDirective,
11543   ngModelDirective,
11544   ngListDirective,
11545   ngChangeDirective,
11546   patternDirective,
11547   patternDirective,
11548   requiredDirective,
11549   requiredDirective,
11550   minlengthDirective,
11551   minlengthDirective,
11552   maxlengthDirective,
11553   maxlengthDirective,
11554   ngValueDirective,
11555   ngModelOptionsDirective,
11556   ngAttributeAliasDirectives,
11557   ngEventDirectives,
11558
11559   $AnchorScrollProvider,
11560   $AnimateProvider,
11561   $CoreAnimateCssProvider,
11562   $$CoreAnimateJsProvider,
11563   $$CoreAnimateQueueProvider,
11564   $$AnimateRunnerFactoryProvider,
11565   $$AnimateAsyncRunFactoryProvider,
11566   $BrowserProvider,
11567   $CacheFactoryProvider,
11568   $ControllerProvider,
11569   $DateProvider,
11570   $DocumentProvider,
11571   $ExceptionHandlerProvider,
11572   $FilterProvider,
11573   $$ForceReflowProvider,
11574   $InterpolateProvider,
11575   $IntervalProvider,
11576   $$HashMapProvider,
11577   $HttpProvider,
11578   $HttpParamSerializerProvider,
11579   $HttpParamSerializerJQLikeProvider,
11580   $HttpBackendProvider,
11581   $xhrFactoryProvider,
11582   $LocationProvider,
11583   $LogProvider,
11584   $ParseProvider,
11585   $RootScopeProvider,
11586   $QProvider,
11587   $$QProvider,
11588   $$SanitizeUriProvider,
11589   $SceProvider,
11590   $SceDelegateProvider,
11591   $SnifferProvider,
11592   $TemplateCacheProvider,
11593   $TemplateRequestProvider,
11594   $$TestabilityProvider,
11595   $TimeoutProvider,
11596   $$RAFProvider,
11597   $WindowProvider,
11598   $$jqLiteProvider,
11599   $$CookieReaderProvider
11600 */
11601
11602
11603 /**
11604  * @ngdoc object
11605  * @name angular.version
11606  * @module ng
11607  * @description
11608  * An object that contains information about the current AngularJS version.
11609  *
11610  * This object has the following properties:
11611  *
11612  * - `full` – `{string}` – Full version string, such as "0.9.18".
11613  * - `major` – `{number}` – Major version number, such as "0".
11614  * - `minor` – `{number}` – Minor version number, such as "9".
11615  * - `dot` – `{number}` – Dot version number, such as "18".
11616  * - `codeName` – `{string}` – Code name of the release, such as "jiggling-armfat".
11617  */
11618 var version = {
11619   full: '1.5.0',    // all of these placeholder strings will be replaced by grunt's
11620   major: 1,    // package task
11621   minor: 5,
11622   dot: 0,
11623   codeName: 'ennoblement-facilitation'
11624 };
11625
11626
11627 function publishExternalAPI(angular) {
11628   extend(angular, {
11629     'bootstrap': bootstrap,
11630     'copy': copy,
11631     'extend': extend,
11632     'merge': merge,
11633     'equals': equals,
11634     'element': jqLite,
11635     'forEach': forEach,
11636     'injector': createInjector,
11637     'noop': noop,
11638     'bind': bind,
11639     'toJson': toJson,
11640     'fromJson': fromJson,
11641     'identity': identity,
11642     'isUndefined': isUndefined,
11643     'isDefined': isDefined,
11644     'isString': isString,
11645     'isFunction': isFunction,
11646     'isObject': isObject,
11647     'isNumber': isNumber,
11648     'isElement': isElement,
11649     'isArray': isArray,
11650     'version': version,
11651     'isDate': isDate,
11652     'lowercase': lowercase,
11653     'uppercase': uppercase,
11654     'callbacks': {counter: 0},
11655     'getTestability': getTestability,
11656     '$$minErr': minErr,
11657     '$$csp': csp,
11658     'reloadWithDebugInfo': reloadWithDebugInfo
11659   });
11660
11661   angularModule = setupModuleLoader(window);
11662
11663   angularModule('ng', ['ngLocale'], ['$provide',
11664     function ngModule($provide) {
11665       // $$sanitizeUriProvider needs to be before $compileProvider as it is used by it.
11666       $provide.provider({
11667         $$sanitizeUri: $$SanitizeUriProvider
11668       });
11669       $provide.provider('$compile', $CompileProvider).
11670         directive({
11671             a: htmlAnchorDirective,
11672             input: inputDirective,
11673             textarea: inputDirective,
11674             form: formDirective,
11675             script: scriptDirective,
11676             select: selectDirective,
11677             style: styleDirective,
11678             option: optionDirective,
11679             ngBind: ngBindDirective,
11680             ngBindHtml: ngBindHtmlDirective,
11681             ngBindTemplate: ngBindTemplateDirective,
11682             ngClass: ngClassDirective,
11683             ngClassEven: ngClassEvenDirective,
11684             ngClassOdd: ngClassOddDirective,
11685             ngCloak: ngCloakDirective,
11686             ngController: ngControllerDirective,
11687             ngForm: ngFormDirective,
11688             ngHide: ngHideDirective,
11689             ngIf: ngIfDirective,
11690             ngInclude: ngIncludeDirective,
11691             ngInit: ngInitDirective,
11692             ngNonBindable: ngNonBindableDirective,
11693             ngPluralize: ngPluralizeDirective,
11694             ngRepeat: ngRepeatDirective,
11695             ngShow: ngShowDirective,
11696             ngStyle: ngStyleDirective,
11697             ngSwitch: ngSwitchDirective,
11698             ngSwitchWhen: ngSwitchWhenDirective,
11699             ngSwitchDefault: ngSwitchDefaultDirective,
11700             ngOptions: ngOptionsDirective,
11701             ngTransclude: ngTranscludeDirective,
11702             ngModel: ngModelDirective,
11703             ngList: ngListDirective,
11704             ngChange: ngChangeDirective,
11705             pattern: patternDirective,
11706             ngPattern: patternDirective,
11707             required: requiredDirective,
11708             ngRequired: requiredDirective,
11709             minlength: minlengthDirective,
11710             ngMinlength: minlengthDirective,
11711             maxlength: maxlengthDirective,
11712             ngMaxlength: maxlengthDirective,
11713             ngValue: ngValueDirective,
11714             ngModelOptions: ngModelOptionsDirective
11715         }).
11716         directive({
11717           ngInclude: ngIncludeFillContentDirective
11718         }).
11719         directive(ngAttributeAliasDirectives).
11720         directive(ngEventDirectives);
11721       $provide.provider({
11722         $anchorScroll: $AnchorScrollProvider,
11723         $animate: $AnimateProvider,
11724         $animateCss: $CoreAnimateCssProvider,
11725         $$animateJs: $$CoreAnimateJsProvider,
11726         $$animateQueue: $$CoreAnimateQueueProvider,
11727         $$AnimateRunner: $$AnimateRunnerFactoryProvider,
11728         $$animateAsyncRun: $$AnimateAsyncRunFactoryProvider,
11729         $browser: $BrowserProvider,
11730         $cacheFactory: $CacheFactoryProvider,
11731         $controller: $ControllerProvider,
11732         $document: $DocumentProvider,
11733         $exceptionHandler: $ExceptionHandlerProvider,
11734         $filter: $FilterProvider,
11735         $$forceReflow: $$ForceReflowProvider,
11736         $interpolate: $InterpolateProvider,
11737         $interval: $IntervalProvider,
11738         $http: $HttpProvider,
11739         $httpParamSerializer: $HttpParamSerializerProvider,
11740         $httpParamSerializerJQLike: $HttpParamSerializerJQLikeProvider,
11741         $httpBackend: $HttpBackendProvider,
11742         $xhrFactory: $xhrFactoryProvider,
11743         $location: $LocationProvider,
11744         $log: $LogProvider,
11745         $parse: $ParseProvider,
11746         $rootScope: $RootScopeProvider,
11747         $q: $QProvider,
11748         $$q: $$QProvider,
11749         $sce: $SceProvider,
11750         $sceDelegate: $SceDelegateProvider,
11751         $sniffer: $SnifferProvider,
11752         $templateCache: $TemplateCacheProvider,
11753         $templateRequest: $TemplateRequestProvider,
11754         $$testability: $$TestabilityProvider,
11755         $timeout: $TimeoutProvider,
11756         $window: $WindowProvider,
11757         $$rAF: $$RAFProvider,
11758         $$jqLite: $$jqLiteProvider,
11759         $$HashMap: $$HashMapProvider,
11760         $$cookieReader: $$CookieReaderProvider
11761       });
11762     }
11763   ]);
11764 }
11765
11766 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
11767  *     Any commits to this file should be reviewed with security in mind.  *
11768  *   Changes to this file can potentially create security vulnerabilities. *
11769  *          An approval from 2 Core members with history of modifying      *
11770  *                         this file is required.                          *
11771  *                                                                         *
11772  *  Does the change somehow allow for arbitrary javascript to be executed? *
11773  *    Or allows for someone to change the prototype of built-in objects?   *
11774  *     Or gives undesired access to variables likes document or window?    *
11775  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
11776
11777 /* global JQLitePrototype: true,
11778   addEventListenerFn: true,
11779   removeEventListenerFn: true,
11780   BOOLEAN_ATTR: true,
11781   ALIASED_ATTR: true,
11782 */
11783
11784 //////////////////////////////////
11785 //JQLite
11786 //////////////////////////////////
11787
11788 /**
11789  * @ngdoc function
11790  * @name angular.element
11791  * @module ng
11792  * @kind function
11793  *
11794  * @description
11795  * Wraps a raw DOM element or HTML string as a [jQuery](http://jquery.com) element.
11796  *
11797  * If jQuery is available, `angular.element` is an alias for the
11798  * [jQuery](http://api.jquery.com/jQuery/) function. If jQuery is not available, `angular.element`
11799  * delegates to Angular's built-in subset of jQuery, called "jQuery lite" or **jqLite**.
11800  *
11801  * jqLite is a tiny, API-compatible subset of jQuery that allows
11802  * Angular to manipulate the DOM in a cross-browser compatible way. jqLite implements only the most
11803  * commonly needed functionality with the goal of having a very small footprint.
11804  *
11805  * To use `jQuery`, simply ensure it is loaded before the `angular.js` file. You can also use the
11806  * {@link ngJq `ngJq`} directive to specify that jqlite should be used over jQuery, or to use a
11807  * specific version of jQuery if multiple versions exist on the page.
11808  *
11809  * <div class="alert alert-info">**Note:** All element references in Angular are always wrapped with jQuery or
11810  * jqLite (such as the element argument in a directive's compile / link function). They are never raw DOM references.</div>
11811  *
11812  * <div class="alert alert-warning">**Note:** Keep in mind that this function will not find elements
11813  * by tag name / CSS selector. For lookups by tag name, try instead `angular.element(document).find(...)`
11814  * or `$document.find()`, or use the standard DOM APIs, e.g. `document.querySelectorAll()`.</div>
11815  *
11816  * ## Angular's jqLite
11817  * jqLite provides only the following jQuery methods:
11818  *
11819  * - [`addClass()`](http://api.jquery.com/addClass/)
11820  * - [`after()`](http://api.jquery.com/after/)
11821  * - [`append()`](http://api.jquery.com/append/)
11822  * - [`attr()`](http://api.jquery.com/attr/) - Does not support functions as parameters
11823  * - [`bind()`](http://api.jquery.com/bind/) - Does not support namespaces, selectors or eventData
11824  * - [`children()`](http://api.jquery.com/children/) - Does not support selectors
11825  * - [`clone()`](http://api.jquery.com/clone/)
11826  * - [`contents()`](http://api.jquery.com/contents/)
11827  * - [`css()`](http://api.jquery.com/css/) - Only retrieves inline-styles, does not call `getComputedStyle()`.
11828  *   As a setter, does not convert numbers to strings or append 'px', and also does not have automatic property prefixing.
11829  * - [`data()`](http://api.jquery.com/data/)
11830  * - [`detach()`](http://api.jquery.com/detach/)
11831  * - [`empty()`](http://api.jquery.com/empty/)
11832  * - [`eq()`](http://api.jquery.com/eq/)
11833  * - [`find()`](http://api.jquery.com/find/) - Limited to lookups by tag name
11834  * - [`hasClass()`](http://api.jquery.com/hasClass/)
11835  * - [`html()`](http://api.jquery.com/html/)
11836  * - [`next()`](http://api.jquery.com/next/) - Does not support selectors
11837  * - [`on()`](http://api.jquery.com/on/) - Does not support namespaces, selectors or eventData
11838  * - [`off()`](http://api.jquery.com/off/) - Does not support namespaces, selectors or event object as parameter
11839  * - [`one()`](http://api.jquery.com/one/) - Does not support namespaces or selectors
11840  * - [`parent()`](http://api.jquery.com/parent/) - Does not support selectors
11841  * - [`prepend()`](http://api.jquery.com/prepend/)
11842  * - [`prop()`](http://api.jquery.com/prop/)
11843  * - [`ready()`](http://api.jquery.com/ready/)
11844  * - [`remove()`](http://api.jquery.com/remove/)
11845  * - [`removeAttr()`](http://api.jquery.com/removeAttr/)
11846  * - [`removeClass()`](http://api.jquery.com/removeClass/)
11847  * - [`removeData()`](http://api.jquery.com/removeData/)
11848  * - [`replaceWith()`](http://api.jquery.com/replaceWith/)
11849  * - [`text()`](http://api.jquery.com/text/)
11850  * - [`toggleClass()`](http://api.jquery.com/toggleClass/)
11851  * - [`triggerHandler()`](http://api.jquery.com/triggerHandler/) - Passes a dummy event object to handlers.
11852  * - [`unbind()`](http://api.jquery.com/unbind/) - Does not support namespaces or event object as parameter
11853  * - [`val()`](http://api.jquery.com/val/)
11854  * - [`wrap()`](http://api.jquery.com/wrap/)
11855  *
11856  * ## jQuery/jqLite Extras
11857  * Angular also provides the following additional methods and events to both jQuery and jqLite:
11858  *
11859  * ### Events
11860  * - `$destroy` - AngularJS intercepts all jqLite/jQuery's DOM destruction apis and fires this event
11861  *    on all DOM nodes being removed.  This can be used to clean up any 3rd party bindings to the DOM
11862  *    element before it is removed.
11863  *
11864  * ### Methods
11865  * - `controller(name)` - retrieves the controller of the current element or its parent. By default
11866  *   retrieves controller associated with the `ngController` directive. If `name` is provided as
11867  *   camelCase directive name, then the controller for this directive will be retrieved (e.g.
11868  *   `'ngModel'`).
11869  * - `injector()` - retrieves the injector of the current element or its parent.
11870  * - `scope()` - retrieves the {@link ng.$rootScope.Scope scope} of the current
11871  *   element or its parent. Requires {@link guide/production#disabling-debug-data Debug Data} to
11872  *   be enabled.
11873  * - `isolateScope()` - retrieves an isolate {@link ng.$rootScope.Scope scope} if one is attached directly to the
11874  *   current element. This getter should be used only on elements that contain a directive which starts a new isolate
11875  *   scope. Calling `scope()` on this element always returns the original non-isolate scope.
11876  *   Requires {@link guide/production#disabling-debug-data Debug Data} to be enabled.
11877  * - `inheritedData()` - same as `data()`, but walks up the DOM until a value is found or the top
11878  *   parent element is reached.
11879  *
11880  * @param {string|DOMElement} element HTML string or DOMElement to be wrapped into jQuery.
11881  * @returns {Object} jQuery object.
11882  */
11883
11884 JQLite.expando = 'ng339';
11885
11886 var jqCache = JQLite.cache = {},
11887     jqId = 1,
11888     addEventListenerFn = function(element, type, fn) {
11889       element.addEventListener(type, fn, false);
11890     },
11891     removeEventListenerFn = function(element, type, fn) {
11892       element.removeEventListener(type, fn, false);
11893     };
11894
11895 /*
11896  * !!! This is an undocumented "private" function !!!
11897  */
11898 JQLite._data = function(node) {
11899   //jQuery always returns an object on cache miss
11900   return this.cache[node[this.expando]] || {};
11901 };
11902
11903 function jqNextId() { return ++jqId; }
11904
11905
11906 var SPECIAL_CHARS_REGEXP = /([\:\-\_]+(.))/g;
11907 var MOZ_HACK_REGEXP = /^moz([A-Z])/;
11908 var MOUSE_EVENT_MAP= { mouseleave: "mouseout", mouseenter: "mouseover"};
11909 var jqLiteMinErr = minErr('jqLite');
11910
11911 /**
11912  * Converts snake_case to camelCase.
11913  * Also there is special case for Moz prefix starting with upper case letter.
11914  * @param name Name to normalize
11915  */
11916 function camelCase(name) {
11917   return name.
11918     replace(SPECIAL_CHARS_REGEXP, function(_, separator, letter, offset) {
11919       return offset ? letter.toUpperCase() : letter;
11920     }).
11921     replace(MOZ_HACK_REGEXP, 'Moz$1');
11922 }
11923
11924 var SINGLE_TAG_REGEXP = /^<([\w-]+)\s*\/?>(?:<\/\1>|)$/;
11925 var HTML_REGEXP = /<|&#?\w+;/;
11926 var TAG_NAME_REGEXP = /<([\w:-]+)/;
11927 var XHTML_TAG_REGEXP = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:-]+)[^>]*)\/>/gi;
11928
11929 var wrapMap = {
11930   'option': [1, '<select multiple="multiple">', '</select>'],
11931
11932   'thead': [1, '<table>', '</table>'],
11933   'col': [2, '<table><colgroup>', '</colgroup></table>'],
11934   'tr': [2, '<table><tbody>', '</tbody></table>'],
11935   'td': [3, '<table><tbody><tr>', '</tr></tbody></table>'],
11936   '_default': [0, "", ""]
11937 };
11938
11939 wrapMap.optgroup = wrapMap.option;
11940 wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
11941 wrapMap.th = wrapMap.td;
11942
11943
11944 function jqLiteIsTextNode(html) {
11945   return !HTML_REGEXP.test(html);
11946 }
11947
11948 function jqLiteAcceptsData(node) {
11949   // The window object can accept data but has no nodeType
11950   // Otherwise we are only interested in elements (1) and documents (9)
11951   var nodeType = node.nodeType;
11952   return nodeType === NODE_TYPE_ELEMENT || !nodeType || nodeType === NODE_TYPE_DOCUMENT;
11953 }
11954
11955 function jqLiteHasData(node) {
11956   for (var key in jqCache[node.ng339]) {
11957     return true;
11958   }
11959   return false;
11960 }
11961
11962 function jqLiteCleanData(nodes) {
11963   for (var i = 0, ii = nodes.length; i < ii; i++) {
11964     jqLiteRemoveData(nodes[i]);
11965   }
11966 }
11967
11968 function jqLiteBuildFragment(html, context) {
11969   var tmp, tag, wrap,
11970       fragment = context.createDocumentFragment(),
11971       nodes = [], i;
11972
11973   if (jqLiteIsTextNode(html)) {
11974     // Convert non-html into a text node
11975     nodes.push(context.createTextNode(html));
11976   } else {
11977     // Convert html into DOM nodes
11978     tmp = tmp || fragment.appendChild(context.createElement("div"));
11979     tag = (TAG_NAME_REGEXP.exec(html) || ["", ""])[1].toLowerCase();
11980     wrap = wrapMap[tag] || wrapMap._default;
11981     tmp.innerHTML = wrap[1] + html.replace(XHTML_TAG_REGEXP, "<$1></$2>") + wrap[2];
11982
11983     // Descend through wrappers to the right content
11984     i = wrap[0];
11985     while (i--) {
11986       tmp = tmp.lastChild;
11987     }
11988
11989     nodes = concat(nodes, tmp.childNodes);
11990
11991     tmp = fragment.firstChild;
11992     tmp.textContent = "";
11993   }
11994
11995   // Remove wrapper from fragment
11996   fragment.textContent = "";
11997   fragment.innerHTML = ""; // Clear inner HTML
11998   forEach(nodes, function(node) {
11999     fragment.appendChild(node);
12000   });
12001
12002   return fragment;
12003 }
12004
12005 function jqLiteParseHTML(html, context) {
12006   context = context || document;
12007   var parsed;
12008
12009   if ((parsed = SINGLE_TAG_REGEXP.exec(html))) {
12010     return [context.createElement(parsed[1])];
12011   }
12012
12013   if ((parsed = jqLiteBuildFragment(html, context))) {
12014     return parsed.childNodes;
12015   }
12016
12017   return [];
12018 }
12019
12020 function jqLiteWrapNode(node, wrapper) {
12021   var parent = node.parentNode;
12022
12023   if (parent) {
12024     parent.replaceChild(wrapper, node);
12025   }
12026
12027   wrapper.appendChild(node);
12028 }
12029
12030
12031 // IE9-11 has no method "contains" in SVG element and in Node.prototype. Bug #10259.
12032 var jqLiteContains = Node.prototype.contains || function(arg) {
12033   // jshint bitwise: false
12034   return !!(this.compareDocumentPosition(arg) & 16);
12035   // jshint bitwise: true
12036 };
12037
12038 /////////////////////////////////////////////
12039 function JQLite(element) {
12040   if (element instanceof JQLite) {
12041     return element;
12042   }
12043
12044   var argIsString;
12045
12046   if (isString(element)) {
12047     element = trim(element);
12048     argIsString = true;
12049   }
12050   if (!(this instanceof JQLite)) {
12051     if (argIsString && element.charAt(0) != '<') {
12052       throw jqLiteMinErr('nosel', 'Looking up elements via selectors is not supported by jqLite! See: http://docs.angularjs.org/api/angular.element');
12053     }
12054     return new JQLite(element);
12055   }
12056
12057   if (argIsString) {
12058     jqLiteAddNodes(this, jqLiteParseHTML(element));
12059   } else {
12060     jqLiteAddNodes(this, element);
12061   }
12062 }
12063
12064 function jqLiteClone(element) {
12065   return element.cloneNode(true);
12066 }
12067
12068 function jqLiteDealoc(element, onlyDescendants) {
12069   if (!onlyDescendants) jqLiteRemoveData(element);
12070
12071   if (element.querySelectorAll) {
12072     var descendants = element.querySelectorAll('*');
12073     for (var i = 0, l = descendants.length; i < l; i++) {
12074       jqLiteRemoveData(descendants[i]);
12075     }
12076   }
12077 }
12078
12079 function jqLiteOff(element, type, fn, unsupported) {
12080   if (isDefined(unsupported)) throw jqLiteMinErr('offargs', 'jqLite#off() does not support the `selector` argument');
12081
12082   var expandoStore = jqLiteExpandoStore(element);
12083   var events = expandoStore && expandoStore.events;
12084   var handle = expandoStore && expandoStore.handle;
12085
12086   if (!handle) return; //no listeners registered
12087
12088   if (!type) {
12089     for (type in events) {
12090       if (type !== '$destroy') {
12091         removeEventListenerFn(element, type, handle);
12092       }
12093       delete events[type];
12094     }
12095   } else {
12096
12097     var removeHandler = function(type) {
12098       var listenerFns = events[type];
12099       if (isDefined(fn)) {
12100         arrayRemove(listenerFns || [], fn);
12101       }
12102       if (!(isDefined(fn) && listenerFns && listenerFns.length > 0)) {
12103         removeEventListenerFn(element, type, handle);
12104         delete events[type];
12105       }
12106     };
12107
12108     forEach(type.split(' '), function(type) {
12109       removeHandler(type);
12110       if (MOUSE_EVENT_MAP[type]) {
12111         removeHandler(MOUSE_EVENT_MAP[type]);
12112       }
12113     });
12114   }
12115 }
12116
12117 function jqLiteRemoveData(element, name) {
12118   var expandoId = element.ng339;
12119   var expandoStore = expandoId && jqCache[expandoId];
12120
12121   if (expandoStore) {
12122     if (name) {
12123       delete expandoStore.data[name];
12124       return;
12125     }
12126
12127     if (expandoStore.handle) {
12128       if (expandoStore.events.$destroy) {
12129         expandoStore.handle({}, '$destroy');
12130       }
12131       jqLiteOff(element);
12132     }
12133     delete jqCache[expandoId];
12134     element.ng339 = undefined; // don't delete DOM expandos. IE and Chrome don't like it
12135   }
12136 }
12137
12138
12139 function jqLiteExpandoStore(element, createIfNecessary) {
12140   var expandoId = element.ng339,
12141       expandoStore = expandoId && jqCache[expandoId];
12142
12143   if (createIfNecessary && !expandoStore) {
12144     element.ng339 = expandoId = jqNextId();
12145     expandoStore = jqCache[expandoId] = {events: {}, data: {}, handle: undefined};
12146   }
12147
12148   return expandoStore;
12149 }
12150
12151
12152 function jqLiteData(element, key, value) {
12153   if (jqLiteAcceptsData(element)) {
12154
12155     var isSimpleSetter = isDefined(value);
12156     var isSimpleGetter = !isSimpleSetter && key && !isObject(key);
12157     var massGetter = !key;
12158     var expandoStore = jqLiteExpandoStore(element, !isSimpleGetter);
12159     var data = expandoStore && expandoStore.data;
12160
12161     if (isSimpleSetter) { // data('key', value)
12162       data[key] = value;
12163     } else {
12164       if (massGetter) {  // data()
12165         return data;
12166       } else {
12167         if (isSimpleGetter) { // data('key')
12168           // don't force creation of expandoStore if it doesn't exist yet
12169           return data && data[key];
12170         } else { // mass-setter: data({key1: val1, key2: val2})
12171           extend(data, key);
12172         }
12173       }
12174     }
12175   }
12176 }
12177
12178 function jqLiteHasClass(element, selector) {
12179   if (!element.getAttribute) return false;
12180   return ((" " + (element.getAttribute('class') || '') + " ").replace(/[\n\t]/g, " ").
12181       indexOf(" " + selector + " ") > -1);
12182 }
12183
12184 function jqLiteRemoveClass(element, cssClasses) {
12185   if (cssClasses && element.setAttribute) {
12186     forEach(cssClasses.split(' '), function(cssClass) {
12187       element.setAttribute('class', trim(
12188           (" " + (element.getAttribute('class') || '') + " ")
12189           .replace(/[\n\t]/g, " ")
12190           .replace(" " + trim(cssClass) + " ", " "))
12191       );
12192     });
12193   }
12194 }
12195
12196 function jqLiteAddClass(element, cssClasses) {
12197   if (cssClasses && element.setAttribute) {
12198     var existingClasses = (' ' + (element.getAttribute('class') || '') + ' ')
12199                             .replace(/[\n\t]/g, " ");
12200
12201     forEach(cssClasses.split(' '), function(cssClass) {
12202       cssClass = trim(cssClass);
12203       if (existingClasses.indexOf(' ' + cssClass + ' ') === -1) {
12204         existingClasses += cssClass + ' ';
12205       }
12206     });
12207
12208     element.setAttribute('class', trim(existingClasses));
12209   }
12210 }
12211
12212
12213 function jqLiteAddNodes(root, elements) {
12214   // THIS CODE IS VERY HOT. Don't make changes without benchmarking.
12215
12216   if (elements) {
12217
12218     // if a Node (the most common case)
12219     if (elements.nodeType) {
12220       root[root.length++] = elements;
12221     } else {
12222       var length = elements.length;
12223
12224       // if an Array or NodeList and not a Window
12225       if (typeof length === 'number' && elements.window !== elements) {
12226         if (length) {
12227           for (var i = 0; i < length; i++) {
12228             root[root.length++] = elements[i];
12229           }
12230         }
12231       } else {
12232         root[root.length++] = elements;
12233       }
12234     }
12235   }
12236 }
12237
12238
12239 function jqLiteController(element, name) {
12240   return jqLiteInheritedData(element, '$' + (name || 'ngController') + 'Controller');
12241 }
12242
12243 function jqLiteInheritedData(element, name, value) {
12244   // if element is the document object work with the html element instead
12245   // this makes $(document).scope() possible
12246   if (element.nodeType == NODE_TYPE_DOCUMENT) {
12247     element = element.documentElement;
12248   }
12249   var names = isArray(name) ? name : [name];
12250
12251   while (element) {
12252     for (var i = 0, ii = names.length; i < ii; i++) {
12253       if (isDefined(value = jqLite.data(element, names[i]))) return value;
12254     }
12255
12256     // If dealing with a document fragment node with a host element, and no parent, use the host
12257     // element as the parent. This enables directives within a Shadow DOM or polyfilled Shadow DOM
12258     // to lookup parent controllers.
12259     element = element.parentNode || (element.nodeType === NODE_TYPE_DOCUMENT_FRAGMENT && element.host);
12260   }
12261 }
12262
12263 function jqLiteEmpty(element) {
12264   jqLiteDealoc(element, true);
12265   while (element.firstChild) {
12266     element.removeChild(element.firstChild);
12267   }
12268 }
12269
12270 function jqLiteRemove(element, keepData) {
12271   if (!keepData) jqLiteDealoc(element);
12272   var parent = element.parentNode;
12273   if (parent) parent.removeChild(element);
12274 }
12275
12276
12277 function jqLiteDocumentLoaded(action, win) {
12278   win = win || window;
12279   if (win.document.readyState === 'complete') {
12280     // Force the action to be run async for consistent behavior
12281     // from the action's point of view
12282     // i.e. it will definitely not be in a $apply
12283     win.setTimeout(action);
12284   } else {
12285     // No need to unbind this handler as load is only ever called once
12286     jqLite(win).on('load', action);
12287   }
12288 }
12289
12290 //////////////////////////////////////////
12291 // Functions which are declared directly.
12292 //////////////////////////////////////////
12293 var JQLitePrototype = JQLite.prototype = {
12294   ready: function(fn) {
12295     var fired = false;
12296
12297     function trigger() {
12298       if (fired) return;
12299       fired = true;
12300       fn();
12301     }
12302
12303     // check if document is already loaded
12304     if (document.readyState === 'complete') {
12305       setTimeout(trigger);
12306     } else {
12307       this.on('DOMContentLoaded', trigger); // works for modern browsers and IE9
12308       // we can not use jqLite since we are not done loading and jQuery could be loaded later.
12309       // jshint -W064
12310       JQLite(window).on('load', trigger); // fallback to window.onload for others
12311       // jshint +W064
12312     }
12313   },
12314   toString: function() {
12315     var value = [];
12316     forEach(this, function(e) { value.push('' + e);});
12317     return '[' + value.join(', ') + ']';
12318   },
12319
12320   eq: function(index) {
12321       return (index >= 0) ? jqLite(this[index]) : jqLite(this[this.length + index]);
12322   },
12323
12324   length: 0,
12325   push: push,
12326   sort: [].sort,
12327   splice: [].splice
12328 };
12329
12330 //////////////////////////////////////////
12331 // Functions iterating getter/setters.
12332 // these functions return self on setter and
12333 // value on get.
12334 //////////////////////////////////////////
12335 var BOOLEAN_ATTR = {};
12336 forEach('multiple,selected,checked,disabled,readOnly,required,open'.split(','), function(value) {
12337   BOOLEAN_ATTR[lowercase(value)] = value;
12338 });
12339 var BOOLEAN_ELEMENTS = {};
12340 forEach('input,select,option,textarea,button,form,details'.split(','), function(value) {
12341   BOOLEAN_ELEMENTS[value] = true;
12342 });
12343 var ALIASED_ATTR = {
12344   'ngMinlength': 'minlength',
12345   'ngMaxlength': 'maxlength',
12346   'ngMin': 'min',
12347   'ngMax': 'max',
12348   'ngPattern': 'pattern'
12349 };
12350
12351 function getBooleanAttrName(element, name) {
12352   // check dom last since we will most likely fail on name
12353   var booleanAttr = BOOLEAN_ATTR[name.toLowerCase()];
12354
12355   // booleanAttr is here twice to minimize DOM access
12356   return booleanAttr && BOOLEAN_ELEMENTS[nodeName_(element)] && booleanAttr;
12357 }
12358
12359 function getAliasedAttrName(name) {
12360   return ALIASED_ATTR[name];
12361 }
12362
12363 forEach({
12364   data: jqLiteData,
12365   removeData: jqLiteRemoveData,
12366   hasData: jqLiteHasData,
12367   cleanData: jqLiteCleanData
12368 }, function(fn, name) {
12369   JQLite[name] = fn;
12370 });
12371
12372 forEach({
12373   data: jqLiteData,
12374   inheritedData: jqLiteInheritedData,
12375
12376   scope: function(element) {
12377     // Can't use jqLiteData here directly so we stay compatible with jQuery!
12378     return jqLite.data(element, '$scope') || jqLiteInheritedData(element.parentNode || element, ['$isolateScope', '$scope']);
12379   },
12380
12381   isolateScope: function(element) {
12382     // Can't use jqLiteData here directly so we stay compatible with jQuery!
12383     return jqLite.data(element, '$isolateScope') || jqLite.data(element, '$isolateScopeNoTemplate');
12384   },
12385
12386   controller: jqLiteController,
12387
12388   injector: function(element) {
12389     return jqLiteInheritedData(element, '$injector');
12390   },
12391
12392   removeAttr: function(element, name) {
12393     element.removeAttribute(name);
12394   },
12395
12396   hasClass: jqLiteHasClass,
12397
12398   css: function(element, name, value) {
12399     name = camelCase(name);
12400
12401     if (isDefined(value)) {
12402       element.style[name] = value;
12403     } else {
12404       return element.style[name];
12405     }
12406   },
12407
12408   attr: function(element, name, value) {
12409     var nodeType = element.nodeType;
12410     if (nodeType === NODE_TYPE_TEXT || nodeType === NODE_TYPE_ATTRIBUTE || nodeType === NODE_TYPE_COMMENT) {
12411       return;
12412     }
12413     var lowercasedName = lowercase(name);
12414     if (BOOLEAN_ATTR[lowercasedName]) {
12415       if (isDefined(value)) {
12416         if (!!value) {
12417           element[name] = true;
12418           element.setAttribute(name, lowercasedName);
12419         } else {
12420           element[name] = false;
12421           element.removeAttribute(lowercasedName);
12422         }
12423       } else {
12424         return (element[name] ||
12425                  (element.attributes.getNamedItem(name) || noop).specified)
12426                ? lowercasedName
12427                : undefined;
12428       }
12429     } else if (isDefined(value)) {
12430       element.setAttribute(name, value);
12431     } else if (element.getAttribute) {
12432       // the extra argument "2" is to get the right thing for a.href in IE, see jQuery code
12433       // some elements (e.g. Document) don't have get attribute, so return undefined
12434       var ret = element.getAttribute(name, 2);
12435       // normalize non-existing attributes to undefined (as jQuery)
12436       return ret === null ? undefined : ret;
12437     }
12438   },
12439
12440   prop: function(element, name, value) {
12441     if (isDefined(value)) {
12442       element[name] = value;
12443     } else {
12444       return element[name];
12445     }
12446   },
12447
12448   text: (function() {
12449     getText.$dv = '';
12450     return getText;
12451
12452     function getText(element, value) {
12453       if (isUndefined(value)) {
12454         var nodeType = element.nodeType;
12455         return (nodeType === NODE_TYPE_ELEMENT || nodeType === NODE_TYPE_TEXT) ? element.textContent : '';
12456       }
12457       element.textContent = value;
12458     }
12459   })(),
12460
12461   val: function(element, value) {
12462     if (isUndefined(value)) {
12463       if (element.multiple && nodeName_(element) === 'select') {
12464         var result = [];
12465         forEach(element.options, function(option) {
12466           if (option.selected) {
12467             result.push(option.value || option.text);
12468           }
12469         });
12470         return result.length === 0 ? null : result;
12471       }
12472       return element.value;
12473     }
12474     element.value = value;
12475   },
12476
12477   html: function(element, value) {
12478     if (isUndefined(value)) {
12479       return element.innerHTML;
12480     }
12481     jqLiteDealoc(element, true);
12482     element.innerHTML = value;
12483   },
12484
12485   empty: jqLiteEmpty
12486 }, function(fn, name) {
12487   /**
12488    * Properties: writes return selection, reads return first value
12489    */
12490   JQLite.prototype[name] = function(arg1, arg2) {
12491     var i, key;
12492     var nodeCount = this.length;
12493
12494     // jqLiteHasClass has only two arguments, but is a getter-only fn, so we need to special-case it
12495     // in a way that survives minification.
12496     // jqLiteEmpty takes no arguments but is a setter.
12497     if (fn !== jqLiteEmpty &&
12498         (isUndefined((fn.length == 2 && (fn !== jqLiteHasClass && fn !== jqLiteController)) ? arg1 : arg2))) {
12499       if (isObject(arg1)) {
12500
12501         // we are a write, but the object properties are the key/values
12502         for (i = 0; i < nodeCount; i++) {
12503           if (fn === jqLiteData) {
12504             // data() takes the whole object in jQuery
12505             fn(this[i], arg1);
12506           } else {
12507             for (key in arg1) {
12508               fn(this[i], key, arg1[key]);
12509             }
12510           }
12511         }
12512         // return self for chaining
12513         return this;
12514       } else {
12515         // we are a read, so read the first child.
12516         // TODO: do we still need this?
12517         var value = fn.$dv;
12518         // Only if we have $dv do we iterate over all, otherwise it is just the first element.
12519         var jj = (isUndefined(value)) ? Math.min(nodeCount, 1) : nodeCount;
12520         for (var j = 0; j < jj; j++) {
12521           var nodeValue = fn(this[j], arg1, arg2);
12522           value = value ? value + nodeValue : nodeValue;
12523         }
12524         return value;
12525       }
12526     } else {
12527       // we are a write, so apply to all children
12528       for (i = 0; i < nodeCount; i++) {
12529         fn(this[i], arg1, arg2);
12530       }
12531       // return self for chaining
12532       return this;
12533     }
12534   };
12535 });
12536
12537 function createEventHandler(element, events) {
12538   var eventHandler = function(event, type) {
12539     // jQuery specific api
12540     event.isDefaultPrevented = function() {
12541       return event.defaultPrevented;
12542     };
12543
12544     var eventFns = events[type || event.type];
12545     var eventFnsLength = eventFns ? eventFns.length : 0;
12546
12547     if (!eventFnsLength) return;
12548
12549     if (isUndefined(event.immediatePropagationStopped)) {
12550       var originalStopImmediatePropagation = event.stopImmediatePropagation;
12551       event.stopImmediatePropagation = function() {
12552         event.immediatePropagationStopped = true;
12553
12554         if (event.stopPropagation) {
12555           event.stopPropagation();
12556         }
12557
12558         if (originalStopImmediatePropagation) {
12559           originalStopImmediatePropagation.call(event);
12560         }
12561       };
12562     }
12563
12564     event.isImmediatePropagationStopped = function() {
12565       return event.immediatePropagationStopped === true;
12566     };
12567
12568     // Some events have special handlers that wrap the real handler
12569     var handlerWrapper = eventFns.specialHandlerWrapper || defaultHandlerWrapper;
12570
12571     // Copy event handlers in case event handlers array is modified during execution.
12572     if ((eventFnsLength > 1)) {
12573       eventFns = shallowCopy(eventFns);
12574     }
12575
12576     for (var i = 0; i < eventFnsLength; i++) {
12577       if (!event.isImmediatePropagationStopped()) {
12578         handlerWrapper(element, event, eventFns[i]);
12579       }
12580     }
12581   };
12582
12583   // TODO: this is a hack for angularMocks/clearDataCache that makes it possible to deregister all
12584   //       events on `element`
12585   eventHandler.elem = element;
12586   return eventHandler;
12587 }
12588
12589 function defaultHandlerWrapper(element, event, handler) {
12590   handler.call(element, event);
12591 }
12592
12593 function specialMouseHandlerWrapper(target, event, handler) {
12594   // Refer to jQuery's implementation of mouseenter & mouseleave
12595   // Read about mouseenter and mouseleave:
12596   // http://www.quirksmode.org/js/events_mouse.html#link8
12597   var related = event.relatedTarget;
12598   // For mousenter/leave call the handler if related is outside the target.
12599   // NB: No relatedTarget if the mouse left/entered the browser window
12600   if (!related || (related !== target && !jqLiteContains.call(target, related))) {
12601     handler.call(target, event);
12602   }
12603 }
12604
12605 //////////////////////////////////////////
12606 // Functions iterating traversal.
12607 // These functions chain results into a single
12608 // selector.
12609 //////////////////////////////////////////
12610 forEach({
12611   removeData: jqLiteRemoveData,
12612
12613   on: function jqLiteOn(element, type, fn, unsupported) {
12614     if (isDefined(unsupported)) throw jqLiteMinErr('onargs', 'jqLite#on() does not support the `selector` or `eventData` parameters');
12615
12616     // Do not add event handlers to non-elements because they will not be cleaned up.
12617     if (!jqLiteAcceptsData(element)) {
12618       return;
12619     }
12620
12621     var expandoStore = jqLiteExpandoStore(element, true);
12622     var events = expandoStore.events;
12623     var handle = expandoStore.handle;
12624
12625     if (!handle) {
12626       handle = expandoStore.handle = createEventHandler(element, events);
12627     }
12628
12629     // http://jsperf.com/string-indexof-vs-split
12630     var types = type.indexOf(' ') >= 0 ? type.split(' ') : [type];
12631     var i = types.length;
12632
12633     var addHandler = function(type, specialHandlerWrapper, noEventListener) {
12634       var eventFns = events[type];
12635
12636       if (!eventFns) {
12637         eventFns = events[type] = [];
12638         eventFns.specialHandlerWrapper = specialHandlerWrapper;
12639         if (type !== '$destroy' && !noEventListener) {
12640           addEventListenerFn(element, type, handle);
12641         }
12642       }
12643
12644       eventFns.push(fn);
12645     };
12646
12647     while (i--) {
12648       type = types[i];
12649       if (MOUSE_EVENT_MAP[type]) {
12650         addHandler(MOUSE_EVENT_MAP[type], specialMouseHandlerWrapper);
12651         addHandler(type, undefined, true);
12652       } else {
12653         addHandler(type);
12654       }
12655     }
12656   },
12657
12658   off: jqLiteOff,
12659
12660   one: function(element, type, fn) {
12661     element = jqLite(element);
12662
12663     //add the listener twice so that when it is called
12664     //you can remove the original function and still be
12665     //able to call element.off(ev, fn) normally
12666     element.on(type, function onFn() {
12667       element.off(type, fn);
12668       element.off(type, onFn);
12669     });
12670     element.on(type, fn);
12671   },
12672
12673   replaceWith: function(element, replaceNode) {
12674     var index, parent = element.parentNode;
12675     jqLiteDealoc(element);
12676     forEach(new JQLite(replaceNode), function(node) {
12677       if (index) {
12678         parent.insertBefore(node, index.nextSibling);
12679       } else {
12680         parent.replaceChild(node, element);
12681       }
12682       index = node;
12683     });
12684   },
12685
12686   children: function(element) {
12687     var children = [];
12688     forEach(element.childNodes, function(element) {
12689       if (element.nodeType === NODE_TYPE_ELEMENT) {
12690         children.push(element);
12691       }
12692     });
12693     return children;
12694   },
12695
12696   contents: function(element) {
12697     return element.contentDocument || element.childNodes || [];
12698   },
12699
12700   append: function(element, node) {
12701     var nodeType = element.nodeType;
12702     if (nodeType !== NODE_TYPE_ELEMENT && nodeType !== NODE_TYPE_DOCUMENT_FRAGMENT) return;
12703
12704     node = new JQLite(node);
12705
12706     for (var i = 0, ii = node.length; i < ii; i++) {
12707       var child = node[i];
12708       element.appendChild(child);
12709     }
12710   },
12711
12712   prepend: function(element, node) {
12713     if (element.nodeType === NODE_TYPE_ELEMENT) {
12714       var index = element.firstChild;
12715       forEach(new JQLite(node), function(child) {
12716         element.insertBefore(child, index);
12717       });
12718     }
12719   },
12720
12721   wrap: function(element, wrapNode) {
12722     jqLiteWrapNode(element, jqLite(wrapNode).eq(0).clone()[0]);
12723   },
12724
12725   remove: jqLiteRemove,
12726
12727   detach: function(element) {
12728     jqLiteRemove(element, true);
12729   },
12730
12731   after: function(element, newElement) {
12732     var index = element, parent = element.parentNode;
12733     newElement = new JQLite(newElement);
12734
12735     for (var i = 0, ii = newElement.length; i < ii; i++) {
12736       var node = newElement[i];
12737       parent.insertBefore(node, index.nextSibling);
12738       index = node;
12739     }
12740   },
12741
12742   addClass: jqLiteAddClass,
12743   removeClass: jqLiteRemoveClass,
12744
12745   toggleClass: function(element, selector, condition) {
12746     if (selector) {
12747       forEach(selector.split(' '), function(className) {
12748         var classCondition = condition;
12749         if (isUndefined(classCondition)) {
12750           classCondition = !jqLiteHasClass(element, className);
12751         }
12752         (classCondition ? jqLiteAddClass : jqLiteRemoveClass)(element, className);
12753       });
12754     }
12755   },
12756
12757   parent: function(element) {
12758     var parent = element.parentNode;
12759     return parent && parent.nodeType !== NODE_TYPE_DOCUMENT_FRAGMENT ? parent : null;
12760   },
12761
12762   next: function(element) {
12763     return element.nextElementSibling;
12764   },
12765
12766   find: function(element, selector) {
12767     if (element.getElementsByTagName) {
12768       return element.getElementsByTagName(selector);
12769     } else {
12770       return [];
12771     }
12772   },
12773
12774   clone: jqLiteClone,
12775
12776   triggerHandler: function(element, event, extraParameters) {
12777
12778     var dummyEvent, eventFnsCopy, handlerArgs;
12779     var eventName = event.type || event;
12780     var expandoStore = jqLiteExpandoStore(element);
12781     var events = expandoStore && expandoStore.events;
12782     var eventFns = events && events[eventName];
12783
12784     if (eventFns) {
12785       // Create a dummy event to pass to the handlers
12786       dummyEvent = {
12787         preventDefault: function() { this.defaultPrevented = true; },
12788         isDefaultPrevented: function() { return this.defaultPrevented === true; },
12789         stopImmediatePropagation: function() { this.immediatePropagationStopped = true; },
12790         isImmediatePropagationStopped: function() { return this.immediatePropagationStopped === true; },
12791         stopPropagation: noop,
12792         type: eventName,
12793         target: element
12794       };
12795
12796       // If a custom event was provided then extend our dummy event with it
12797       if (event.type) {
12798         dummyEvent = extend(dummyEvent, event);
12799       }
12800
12801       // Copy event handlers in case event handlers array is modified during execution.
12802       eventFnsCopy = shallowCopy(eventFns);
12803       handlerArgs = extraParameters ? [dummyEvent].concat(extraParameters) : [dummyEvent];
12804
12805       forEach(eventFnsCopy, function(fn) {
12806         if (!dummyEvent.isImmediatePropagationStopped()) {
12807           fn.apply(element, handlerArgs);
12808         }
12809       });
12810     }
12811   }
12812 }, function(fn, name) {
12813   /**
12814    * chaining functions
12815    */
12816   JQLite.prototype[name] = function(arg1, arg2, arg3) {
12817     var value;
12818
12819     for (var i = 0, ii = this.length; i < ii; i++) {
12820       if (isUndefined(value)) {
12821         value = fn(this[i], arg1, arg2, arg3);
12822         if (isDefined(value)) {
12823           // any function which returns a value needs to be wrapped
12824           value = jqLite(value);
12825         }
12826       } else {
12827         jqLiteAddNodes(value, fn(this[i], arg1, arg2, arg3));
12828       }
12829     }
12830     return isDefined(value) ? value : this;
12831   };
12832
12833   // bind legacy bind/unbind to on/off
12834   JQLite.prototype.bind = JQLite.prototype.on;
12835   JQLite.prototype.unbind = JQLite.prototype.off;
12836 });
12837
12838
12839 // Provider for private $$jqLite service
12840 function $$jqLiteProvider() {
12841   this.$get = function $$jqLite() {
12842     return extend(JQLite, {
12843       hasClass: function(node, classes) {
12844         if (node.attr) node = node[0];
12845         return jqLiteHasClass(node, classes);
12846       },
12847       addClass: function(node, classes) {
12848         if (node.attr) node = node[0];
12849         return jqLiteAddClass(node, classes);
12850       },
12851       removeClass: function(node, classes) {
12852         if (node.attr) node = node[0];
12853         return jqLiteRemoveClass(node, classes);
12854       }
12855     });
12856   };
12857 }
12858
12859 /**
12860  * Computes a hash of an 'obj'.
12861  * Hash of a:
12862  *  string is string
12863  *  number is number as string
12864  *  object is either result of calling $$hashKey function on the object or uniquely generated id,
12865  *         that is also assigned to the $$hashKey property of the object.
12866  *
12867  * @param obj
12868  * @returns {string} hash string such that the same input will have the same hash string.
12869  *         The resulting string key is in 'type:hashKey' format.
12870  */
12871 function hashKey(obj, nextUidFn) {
12872   var key = obj && obj.$$hashKey;
12873
12874   if (key) {
12875     if (typeof key === 'function') {
12876       key = obj.$$hashKey();
12877     }
12878     return key;
12879   }
12880
12881   var objType = typeof obj;
12882   if (objType == 'function' || (objType == 'object' && obj !== null)) {
12883     key = obj.$$hashKey = objType + ':' + (nextUidFn || nextUid)();
12884   } else {
12885     key = objType + ':' + obj;
12886   }
12887
12888   return key;
12889 }
12890
12891 /**
12892  * HashMap which can use objects as keys
12893  */
12894 function HashMap(array, isolatedUid) {
12895   if (isolatedUid) {
12896     var uid = 0;
12897     this.nextUid = function() {
12898       return ++uid;
12899     };
12900   }
12901   forEach(array, this.put, this);
12902 }
12903 HashMap.prototype = {
12904   /**
12905    * Store key value pair
12906    * @param key key to store can be any type
12907    * @param value value to store can be any type
12908    */
12909   put: function(key, value) {
12910     this[hashKey(key, this.nextUid)] = value;
12911   },
12912
12913   /**
12914    * @param key
12915    * @returns {Object} the value for the key
12916    */
12917   get: function(key) {
12918     return this[hashKey(key, this.nextUid)];
12919   },
12920
12921   /**
12922    * Remove the key/value pair
12923    * @param key
12924    */
12925   remove: function(key) {
12926     var value = this[key = hashKey(key, this.nextUid)];
12927     delete this[key];
12928     return value;
12929   }
12930 };
12931
12932 var $$HashMapProvider = [function() {
12933   this.$get = [function() {
12934     return HashMap;
12935   }];
12936 }];
12937
12938 /**
12939  * @ngdoc function
12940  * @module ng
12941  * @name angular.injector
12942  * @kind function
12943  *
12944  * @description
12945  * Creates an injector object that can be used for retrieving services as well as for
12946  * dependency injection (see {@link guide/di dependency injection}).
12947  *
12948  * @param {Array.<string|Function>} modules A list of module functions or their aliases. See
12949  *     {@link angular.module}. The `ng` module must be explicitly added.
12950  * @param {boolean=} [strictDi=false] Whether the injector should be in strict mode, which
12951  *     disallows argument name annotation inference.
12952  * @returns {injector} Injector object. See {@link auto.$injector $injector}.
12953  *
12954  * @example
12955  * Typical usage
12956  * ```js
12957  *   // create an injector
12958  *   var $injector = angular.injector(['ng']);
12959  *
12960  *   // use the injector to kick off your application
12961  *   // use the type inference to auto inject arguments, or use implicit injection
12962  *   $injector.invoke(function($rootScope, $compile, $document) {
12963  *     $compile($document)($rootScope);
12964  *     $rootScope.$digest();
12965  *   });
12966  * ```
12967  *
12968  * Sometimes you want to get access to the injector of a currently running Angular app
12969  * from outside Angular. Perhaps, you want to inject and compile some markup after the
12970  * application has been bootstrapped. You can do this using the extra `injector()` added
12971  * to JQuery/jqLite elements. See {@link angular.element}.
12972  *
12973  * *This is fairly rare but could be the case if a third party library is injecting the
12974  * markup.*
12975  *
12976  * In the following example a new block of HTML containing a `ng-controller`
12977  * directive is added to the end of the document body by JQuery. We then compile and link
12978  * it into the current AngularJS scope.
12979  *
12980  * ```js
12981  * var $div = $('<div ng-controller="MyCtrl">{{content.label}}</div>');
12982  * $(document.body).append($div);
12983  *
12984  * angular.element(document).injector().invoke(function($compile) {
12985  *   var scope = angular.element($div).scope();
12986  *   $compile($div)(scope);
12987  * });
12988  * ```
12989  */
12990
12991
12992 /**
12993  * @ngdoc module
12994  * @name auto
12995  * @description
12996  *
12997  * Implicit module which gets automatically added to each {@link auto.$injector $injector}.
12998  */
12999
13000 var ARROW_ARG = /^([^\(]+?)=>/;
13001 var FN_ARGS = /^[^\(]*\(\s*([^\)]*)\)/m;
13002 var FN_ARG_SPLIT = /,/;
13003 var FN_ARG = /^\s*(_?)(\S+?)\1\s*$/;
13004 var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;
13005 var $injectorMinErr = minErr('$injector');
13006
13007 function extractArgs(fn) {
13008   var fnText = fn.toString().replace(STRIP_COMMENTS, ''),
13009       args = fnText.match(ARROW_ARG) || fnText.match(FN_ARGS);
13010   return args;
13011 }
13012
13013 function anonFn(fn) {
13014   // For anonymous functions, showing at the very least the function signature can help in
13015   // debugging.
13016   var args = extractArgs(fn);
13017   if (args) {
13018     return 'function(' + (args[1] || '').replace(/[\s\r\n]+/, ' ') + ')';
13019   }
13020   return 'fn';
13021 }
13022
13023 function annotate(fn, strictDi, name) {
13024   var $inject,
13025       argDecl,
13026       last;
13027
13028   if (typeof fn === 'function') {
13029     if (!($inject = fn.$inject)) {
13030       $inject = [];
13031       if (fn.length) {
13032         if (strictDi) {
13033           if (!isString(name) || !name) {
13034             name = fn.name || anonFn(fn);
13035           }
13036           throw $injectorMinErr('strictdi',
13037             '{0} is not using explicit annotation and cannot be invoked in strict mode', name);
13038         }
13039         argDecl = extractArgs(fn);
13040         forEach(argDecl[1].split(FN_ARG_SPLIT), function(arg) {
13041           arg.replace(FN_ARG, function(all, underscore, name) {
13042             $inject.push(name);
13043           });
13044         });
13045       }
13046       fn.$inject = $inject;
13047     }
13048   } else if (isArray(fn)) {
13049     last = fn.length - 1;
13050     assertArgFn(fn[last], 'fn');
13051     $inject = fn.slice(0, last);
13052   } else {
13053     assertArgFn(fn, 'fn', true);
13054   }
13055   return $inject;
13056 }
13057
13058 ///////////////////////////////////////
13059
13060 /**
13061  * @ngdoc service
13062  * @name $injector
13063  *
13064  * @description
13065  *
13066  * `$injector` is used to retrieve object instances as defined by
13067  * {@link auto.$provide provider}, instantiate types, invoke methods,
13068  * and load modules.
13069  *
13070  * The following always holds true:
13071  *
13072  * ```js
13073  *   var $injector = angular.injector();
13074  *   expect($injector.get('$injector')).toBe($injector);
13075  *   expect($injector.invoke(function($injector) {
13076  *     return $injector;
13077  *   })).toBe($injector);
13078  * ```
13079  *
13080  * # Injection Function Annotation
13081  *
13082  * JavaScript does not have annotations, and annotations are needed for dependency injection. The
13083  * following are all valid ways of annotating function with injection arguments and are equivalent.
13084  *
13085  * ```js
13086  *   // inferred (only works if code not minified/obfuscated)
13087  *   $injector.invoke(function(serviceA){});
13088  *
13089  *   // annotated
13090  *   function explicit(serviceA) {};
13091  *   explicit.$inject = ['serviceA'];
13092  *   $injector.invoke(explicit);
13093  *
13094  *   // inline
13095  *   $injector.invoke(['serviceA', function(serviceA){}]);
13096  * ```
13097  *
13098  * ## Inference
13099  *
13100  * In JavaScript calling `toString()` on a function returns the function definition. The definition
13101  * can then be parsed and the function arguments can be extracted. This method of discovering
13102  * annotations is disallowed when the injector is in strict mode.
13103  * *NOTE:* This does not work with minification, and obfuscation tools since these tools change the
13104  * argument names.
13105  *
13106  * ## `$inject` Annotation
13107  * By adding an `$inject` property onto a function the injection parameters can be specified.
13108  *
13109  * ## Inline
13110  * As an array of injection names, where the last item in the array is the function to call.
13111  */
13112
13113 /**
13114  * @ngdoc method
13115  * @name $injector#get
13116  *
13117  * @description
13118  * Return an instance of the service.
13119  *
13120  * @param {string} name The name of the instance to retrieve.
13121  * @param {string=} caller An optional string to provide the origin of the function call for error messages.
13122  * @return {*} The instance.
13123  */
13124
13125 /**
13126  * @ngdoc method
13127  * @name $injector#invoke
13128  *
13129  * @description
13130  * Invoke the method and supply the method arguments from the `$injector`.
13131  *
13132  * @param {Function|Array.<string|Function>} fn The injectable function to invoke. Function parameters are
13133  *   injected according to the {@link guide/di $inject Annotation} rules.
13134  * @param {Object=} self The `this` for the invoked method.
13135  * @param {Object=} locals Optional object. If preset then any argument names are read from this
13136  *                         object first, before the `$injector` is consulted.
13137  * @returns {*} the value returned by the invoked `fn` function.
13138  */
13139
13140 /**
13141  * @ngdoc method
13142  * @name $injector#has
13143  *
13144  * @description
13145  * Allows the user to query if the particular service exists.
13146  *
13147  * @param {string} name Name of the service to query.
13148  * @returns {boolean} `true` if injector has given service.
13149  */
13150
13151 /**
13152  * @ngdoc method
13153  * @name $injector#instantiate
13154  * @description
13155  * Create a new instance of JS type. The method takes a constructor function, invokes the new
13156  * operator, and supplies all of the arguments to the constructor function as specified by the
13157  * constructor annotation.
13158  *
13159  * @param {Function} Type Annotated constructor function.
13160  * @param {Object=} locals Optional object. If preset then any argument names are read from this
13161  * object first, before the `$injector` is consulted.
13162  * @returns {Object} new instance of `Type`.
13163  */
13164
13165 /**
13166  * @ngdoc method
13167  * @name $injector#annotate
13168  *
13169  * @description
13170  * Returns an array of service names which the function is requesting for injection. This API is
13171  * used by the injector to determine which services need to be injected into the function when the
13172  * function is invoked. There are three ways in which the function can be annotated with the needed
13173  * dependencies.
13174  *
13175  * # Argument names
13176  *
13177  * The simplest form is to extract the dependencies from the arguments of the function. This is done
13178  * by converting the function into a string using `toString()` method and extracting the argument
13179  * names.
13180  * ```js
13181  *   // Given
13182  *   function MyController($scope, $route) {
13183  *     // ...
13184  *   }
13185  *
13186  *   // Then
13187  *   expect(injector.annotate(MyController)).toEqual(['$scope', '$route']);
13188  * ```
13189  *
13190  * You can disallow this method by using strict injection mode.
13191  *
13192  * This method does not work with code minification / obfuscation. For this reason the following
13193  * annotation strategies are supported.
13194  *
13195  * # The `$inject` property
13196  *
13197  * If a function has an `$inject` property and its value is an array of strings, then the strings
13198  * represent names of services to be injected into the function.
13199  * ```js
13200  *   // Given
13201  *   var MyController = function(obfuscatedScope, obfuscatedRoute) {
13202  *     // ...
13203  *   }
13204  *   // Define function dependencies
13205  *   MyController['$inject'] = ['$scope', '$route'];
13206  *
13207  *   // Then
13208  *   expect(injector.annotate(MyController)).toEqual(['$scope', '$route']);
13209  * ```
13210  *
13211  * # The array notation
13212  *
13213  * It is often desirable to inline Injected functions and that's when setting the `$inject` property
13214  * is very inconvenient. In these situations using the array notation to specify the dependencies in
13215  * a way that survives minification is a better choice:
13216  *
13217  * ```js
13218  *   // We wish to write this (not minification / obfuscation safe)
13219  *   injector.invoke(function($compile, $rootScope) {
13220  *     // ...
13221  *   });
13222  *
13223  *   // We are forced to write break inlining
13224  *   var tmpFn = function(obfuscatedCompile, obfuscatedRootScope) {
13225  *     // ...
13226  *   };
13227  *   tmpFn.$inject = ['$compile', '$rootScope'];
13228  *   injector.invoke(tmpFn);
13229  *
13230  *   // To better support inline function the inline annotation is supported
13231  *   injector.invoke(['$compile', '$rootScope', function(obfCompile, obfRootScope) {
13232  *     // ...
13233  *   }]);
13234  *
13235  *   // Therefore
13236  *   expect(injector.annotate(
13237  *      ['$compile', '$rootScope', function(obfus_$compile, obfus_$rootScope) {}])
13238  *    ).toEqual(['$compile', '$rootScope']);
13239  * ```
13240  *
13241  * @param {Function|Array.<string|Function>} fn Function for which dependent service names need to
13242  * be retrieved as described above.
13243  *
13244  * @param {boolean=} [strictDi=false] Disallow argument name annotation inference.
13245  *
13246  * @returns {Array.<string>} The names of the services which the function requires.
13247  */
13248
13249
13250
13251
13252 /**
13253  * @ngdoc service
13254  * @name $provide
13255  *
13256  * @description
13257  *
13258  * The {@link auto.$provide $provide} service has a number of methods for registering components
13259  * with the {@link auto.$injector $injector}. Many of these functions are also exposed on
13260  * {@link angular.Module}.
13261  *
13262  * An Angular **service** is a singleton object created by a **service factory**.  These **service
13263  * factories** are functions which, in turn, are created by a **service provider**.
13264  * The **service providers** are constructor functions. When instantiated they must contain a
13265  * property called `$get`, which holds the **service factory** function.
13266  *
13267  * When you request a service, the {@link auto.$injector $injector} is responsible for finding the
13268  * correct **service provider**, instantiating it and then calling its `$get` **service factory**
13269  * function to get the instance of the **service**.
13270  *
13271  * Often services have no configuration options and there is no need to add methods to the service
13272  * provider.  The provider will be no more than a constructor function with a `$get` property. For
13273  * these cases the {@link auto.$provide $provide} service has additional helper methods to register
13274  * services without specifying a provider.
13275  *
13276  * * {@link auto.$provide#provider provider(provider)} - registers a **service provider** with the
13277  *     {@link auto.$injector $injector}
13278  * * {@link auto.$provide#constant constant(obj)} - registers a value/object that can be accessed by
13279  *     providers and services.
13280  * * {@link auto.$provide#value value(obj)} - registers a value/object that can only be accessed by
13281  *     services, not providers.
13282  * * {@link auto.$provide#factory factory(fn)} - registers a service **factory function**, `fn`,
13283  *     that will be wrapped in a **service provider** object, whose `$get` property will contain the
13284  *     given factory function.
13285  * * {@link auto.$provide#service service(class)} - registers a **constructor function**, `class`
13286  *     that will be wrapped in a **service provider** object, whose `$get` property will instantiate
13287  *      a new object using the given constructor function.
13288  *
13289  * See the individual methods for more information and examples.
13290  */
13291
13292 /**
13293  * @ngdoc method
13294  * @name $provide#provider
13295  * @description
13296  *
13297  * Register a **provider function** with the {@link auto.$injector $injector}. Provider functions
13298  * are constructor functions, whose instances are responsible for "providing" a factory for a
13299  * service.
13300  *
13301  * Service provider names start with the name of the service they provide followed by `Provider`.
13302  * For example, the {@link ng.$log $log} service has a provider called
13303  * {@link ng.$logProvider $logProvider}.
13304  *
13305  * Service provider objects can have additional methods which allow configuration of the provider
13306  * and its service. Importantly, you can configure what kind of service is created by the `$get`
13307  * method, or how that service will act. For example, the {@link ng.$logProvider $logProvider} has a
13308  * method {@link ng.$logProvider#debugEnabled debugEnabled}
13309  * which lets you specify whether the {@link ng.$log $log} service will log debug messages to the
13310  * console or not.
13311  *
13312  * @param {string} name The name of the instance. NOTE: the provider will be available under `name +
13313                         'Provider'` key.
13314  * @param {(Object|function())} provider If the provider is:
13315  *
13316  *   - `Object`: then it should have a `$get` method. The `$get` method will be invoked using
13317  *     {@link auto.$injector#invoke $injector.invoke()} when an instance needs to be created.
13318  *   - `Constructor`: a new instance of the provider will be created using
13319  *     {@link auto.$injector#instantiate $injector.instantiate()}, then treated as `object`.
13320  *
13321  * @returns {Object} registered provider instance
13322
13323  * @example
13324  *
13325  * The following example shows how to create a simple event tracking service and register it using
13326  * {@link auto.$provide#provider $provide.provider()}.
13327  *
13328  * ```js
13329  *  // Define the eventTracker provider
13330  *  function EventTrackerProvider() {
13331  *    var trackingUrl = '/track';
13332  *
13333  *    // A provider method for configuring where the tracked events should been saved
13334  *    this.setTrackingUrl = function(url) {
13335  *      trackingUrl = url;
13336  *    };
13337  *
13338  *    // The service factory function
13339  *    this.$get = ['$http', function($http) {
13340  *      var trackedEvents = {};
13341  *      return {
13342  *        // Call this to track an event
13343  *        event: function(event) {
13344  *          var count = trackedEvents[event] || 0;
13345  *          count += 1;
13346  *          trackedEvents[event] = count;
13347  *          return count;
13348  *        },
13349  *        // Call this to save the tracked events to the trackingUrl
13350  *        save: function() {
13351  *          $http.post(trackingUrl, trackedEvents);
13352  *        }
13353  *      };
13354  *    }];
13355  *  }
13356  *
13357  *  describe('eventTracker', function() {
13358  *    var postSpy;
13359  *
13360  *    beforeEach(module(function($provide) {
13361  *      // Register the eventTracker provider
13362  *      $provide.provider('eventTracker', EventTrackerProvider);
13363  *    }));
13364  *
13365  *    beforeEach(module(function(eventTrackerProvider) {
13366  *      // Configure eventTracker provider
13367  *      eventTrackerProvider.setTrackingUrl('/custom-track');
13368  *    }));
13369  *
13370  *    it('tracks events', inject(function(eventTracker) {
13371  *      expect(eventTracker.event('login')).toEqual(1);
13372  *      expect(eventTracker.event('login')).toEqual(2);
13373  *    }));
13374  *
13375  *    it('saves to the tracking url', inject(function(eventTracker, $http) {
13376  *      postSpy = spyOn($http, 'post');
13377  *      eventTracker.event('login');
13378  *      eventTracker.save();
13379  *      expect(postSpy).toHaveBeenCalled();
13380  *      expect(postSpy.mostRecentCall.args[0]).not.toEqual('/track');
13381  *      expect(postSpy.mostRecentCall.args[0]).toEqual('/custom-track');
13382  *      expect(postSpy.mostRecentCall.args[1]).toEqual({ 'login': 1 });
13383  *    }));
13384  *  });
13385  * ```
13386  */
13387
13388 /**
13389  * @ngdoc method
13390  * @name $provide#factory
13391  * @description
13392  *
13393  * Register a **service factory**, which will be called to return the service instance.
13394  * This is short for registering a service where its provider consists of only a `$get` property,
13395  * which is the given service factory function.
13396  * You should use {@link auto.$provide#factory $provide.factory(getFn)} if you do not need to
13397  * configure your service in a provider.
13398  *
13399  * @param {string} name The name of the instance.
13400  * @param {Function|Array.<string|Function>} $getFn The injectable $getFn for the instance creation.
13401  *                      Internally this is a short hand for `$provide.provider(name, {$get: $getFn})`.
13402  * @returns {Object} registered provider instance
13403  *
13404  * @example
13405  * Here is an example of registering a service
13406  * ```js
13407  *   $provide.factory('ping', ['$http', function($http) {
13408  *     return function ping() {
13409  *       return $http.send('/ping');
13410  *     };
13411  *   }]);
13412  * ```
13413  * You would then inject and use this service like this:
13414  * ```js
13415  *   someModule.controller('Ctrl', ['ping', function(ping) {
13416  *     ping();
13417  *   }]);
13418  * ```
13419  */
13420
13421
13422 /**
13423  * @ngdoc method
13424  * @name $provide#service
13425  * @description
13426  *
13427  * Register a **service constructor**, which will be invoked with `new` to create the service
13428  * instance.
13429  * This is short for registering a service where its provider's `$get` property is a factory
13430  * function that returns an instance instantiated by the injector from the service constructor
13431  * function.
13432  *
13433  * Internally it looks a bit like this:
13434  *
13435  * ```
13436  * {
13437  *   $get: function() {
13438  *     return $injector.instantiate(constructor);
13439  *   }
13440  * }
13441  * ```
13442  *
13443  *
13444  * You should use {@link auto.$provide#service $provide.service(class)} if you define your service
13445  * as a type/class.
13446  *
13447  * @param {string} name The name of the instance.
13448  * @param {Function|Array.<string|Function>} constructor An injectable class (constructor function)
13449  *     that will be instantiated.
13450  * @returns {Object} registered provider instance
13451  *
13452  * @example
13453  * Here is an example of registering a service using
13454  * {@link auto.$provide#service $provide.service(class)}.
13455  * ```js
13456  *   var Ping = function($http) {
13457  *     this.$http = $http;
13458  *   };
13459  *
13460  *   Ping.$inject = ['$http'];
13461  *
13462  *   Ping.prototype.send = function() {
13463  *     return this.$http.get('/ping');
13464  *   };
13465  *   $provide.service('ping', Ping);
13466  * ```
13467  * You would then inject and use this service like this:
13468  * ```js
13469  *   someModule.controller('Ctrl', ['ping', function(ping) {
13470  *     ping.send();
13471  *   }]);
13472  * ```
13473  */
13474
13475
13476 /**
13477  * @ngdoc method
13478  * @name $provide#value
13479  * @description
13480  *
13481  * Register a **value service** with the {@link auto.$injector $injector}, such as a string, a
13482  * number, an array, an object or a function.  This is short for registering a service where its
13483  * provider's `$get` property is a factory function that takes no arguments and returns the **value
13484  * service**.
13485  *
13486  * Value services are similar to constant services, except that they cannot be injected into a
13487  * module configuration function (see {@link angular.Module#config}) but they can be overridden by
13488  * an Angular
13489  * {@link auto.$provide#decorator decorator}.
13490  *
13491  * @param {string} name The name of the instance.
13492  * @param {*} value The value.
13493  * @returns {Object} registered provider instance
13494  *
13495  * @example
13496  * Here are some examples of creating value services.
13497  * ```js
13498  *   $provide.value('ADMIN_USER', 'admin');
13499  *
13500  *   $provide.value('RoleLookup', { admin: 0, writer: 1, reader: 2 });
13501  *
13502  *   $provide.value('halfOf', function(value) {
13503  *     return value / 2;
13504  *   });
13505  * ```
13506  */
13507
13508
13509 /**
13510  * @ngdoc method
13511  * @name $provide#constant
13512  * @description
13513  *
13514  * Register a **constant service**, such as a string, a number, an array, an object or a function,
13515  * with the {@link auto.$injector $injector}. Unlike {@link auto.$provide#value value} it can be
13516  * injected into a module configuration function (see {@link angular.Module#config}) and it cannot
13517  * be overridden by an Angular {@link auto.$provide#decorator decorator}.
13518  *
13519  * @param {string} name The name of the constant.
13520  * @param {*} value The constant value.
13521  * @returns {Object} registered instance
13522  *
13523  * @example
13524  * Here a some examples of creating constants:
13525  * ```js
13526  *   $provide.constant('SHARD_HEIGHT', 306);
13527  *
13528  *   $provide.constant('MY_COLOURS', ['red', 'blue', 'grey']);
13529  *
13530  *   $provide.constant('double', function(value) {
13531  *     return value * 2;
13532  *   });
13533  * ```
13534  */
13535
13536
13537 /**
13538  * @ngdoc method
13539  * @name $provide#decorator
13540  * @description
13541  *
13542  * Register a **service decorator** with the {@link auto.$injector $injector}. A service decorator
13543  * intercepts the creation of a service, allowing it to override or modify the behavior of the
13544  * service. The object returned by the decorator may be the original service, or a new service
13545  * object which replaces or wraps and delegates to the original service.
13546  *
13547  * @param {string} name The name of the service to decorate.
13548  * @param {Function|Array.<string|Function>} decorator This function will be invoked when the service needs to be
13549  *    instantiated and should return the decorated service instance. The function is called using
13550  *    the {@link auto.$injector#invoke injector.invoke} method and is therefore fully injectable.
13551  *    Local injection arguments:
13552  *
13553  *    * `$delegate` - The original service instance, which can be monkey patched, configured,
13554  *      decorated or delegated to.
13555  *
13556  * @example
13557  * Here we decorate the {@link ng.$log $log} service to convert warnings to errors by intercepting
13558  * calls to {@link ng.$log#error $log.warn()}.
13559  * ```js
13560  *   $provide.decorator('$log', ['$delegate', function($delegate) {
13561  *     $delegate.warn = $delegate.error;
13562  *     return $delegate;
13563  *   }]);
13564  * ```
13565  */
13566
13567
13568 function createInjector(modulesToLoad, strictDi) {
13569   strictDi = (strictDi === true);
13570   var INSTANTIATING = {},
13571       providerSuffix = 'Provider',
13572       path = [],
13573       loadedModules = new HashMap([], true),
13574       providerCache = {
13575         $provide: {
13576             provider: supportObject(provider),
13577             factory: supportObject(factory),
13578             service: supportObject(service),
13579             value: supportObject(value),
13580             constant: supportObject(constant),
13581             decorator: decorator
13582           }
13583       },
13584       providerInjector = (providerCache.$injector =
13585           createInternalInjector(providerCache, function(serviceName, caller) {
13586             if (angular.isString(caller)) {
13587               path.push(caller);
13588             }
13589             throw $injectorMinErr('unpr', "Unknown provider: {0}", path.join(' <- '));
13590           })),
13591       instanceCache = {},
13592       protoInstanceInjector =
13593           createInternalInjector(instanceCache, function(serviceName, caller) {
13594             var provider = providerInjector.get(serviceName + providerSuffix, caller);
13595             return instanceInjector.invoke(
13596                 provider.$get, provider, undefined, serviceName);
13597           }),
13598       instanceInjector = protoInstanceInjector;
13599
13600   providerCache['$injector' + providerSuffix] = { $get: valueFn(protoInstanceInjector) };
13601   var runBlocks = loadModules(modulesToLoad);
13602   instanceInjector = protoInstanceInjector.get('$injector');
13603   instanceInjector.strictDi = strictDi;
13604   forEach(runBlocks, function(fn) { if (fn) instanceInjector.invoke(fn); });
13605
13606   return instanceInjector;
13607
13608   ////////////////////////////////////
13609   // $provider
13610   ////////////////////////////////////
13611
13612   function supportObject(delegate) {
13613     return function(key, value) {
13614       if (isObject(key)) {
13615         forEach(key, reverseParams(delegate));
13616       } else {
13617         return delegate(key, value);
13618       }
13619     };
13620   }
13621
13622   function provider(name, provider_) {
13623     assertNotHasOwnProperty(name, 'service');
13624     if (isFunction(provider_) || isArray(provider_)) {
13625       provider_ = providerInjector.instantiate(provider_);
13626     }
13627     if (!provider_.$get) {
13628       throw $injectorMinErr('pget', "Provider '{0}' must define $get factory method.", name);
13629     }
13630     return providerCache[name + providerSuffix] = provider_;
13631   }
13632
13633   function enforceReturnValue(name, factory) {
13634     return function enforcedReturnValue() {
13635       var result = instanceInjector.invoke(factory, this);
13636       if (isUndefined(result)) {
13637         throw $injectorMinErr('undef', "Provider '{0}' must return a value from $get factory method.", name);
13638       }
13639       return result;
13640     };
13641   }
13642
13643   function factory(name, factoryFn, enforce) {
13644     return provider(name, {
13645       $get: enforce !== false ? enforceReturnValue(name, factoryFn) : factoryFn
13646     });
13647   }
13648
13649   function service(name, constructor) {
13650     return factory(name, ['$injector', function($injector) {
13651       return $injector.instantiate(constructor);
13652     }]);
13653   }
13654
13655   function value(name, val) { return factory(name, valueFn(val), false); }
13656
13657   function constant(name, value) {
13658     assertNotHasOwnProperty(name, 'constant');
13659     providerCache[name] = value;
13660     instanceCache[name] = value;
13661   }
13662
13663   function decorator(serviceName, decorFn) {
13664     var origProvider = providerInjector.get(serviceName + providerSuffix),
13665         orig$get = origProvider.$get;
13666
13667     origProvider.$get = function() {
13668       var origInstance = instanceInjector.invoke(orig$get, origProvider);
13669       return instanceInjector.invoke(decorFn, null, {$delegate: origInstance});
13670     };
13671   }
13672
13673   ////////////////////////////////////
13674   // Module Loading
13675   ////////////////////////////////////
13676   function loadModules(modulesToLoad) {
13677     assertArg(isUndefined(modulesToLoad) || isArray(modulesToLoad), 'modulesToLoad', 'not an array');
13678     var runBlocks = [], moduleFn;
13679     forEach(modulesToLoad, function(module) {
13680       if (loadedModules.get(module)) return;
13681       loadedModules.put(module, true);
13682
13683       function runInvokeQueue(queue) {
13684         var i, ii;
13685         for (i = 0, ii = queue.length; i < ii; i++) {
13686           var invokeArgs = queue[i],
13687               provider = providerInjector.get(invokeArgs[0]);
13688
13689           provider[invokeArgs[1]].apply(provider, invokeArgs[2]);
13690         }
13691       }
13692
13693       try {
13694         if (isString(module)) {
13695           moduleFn = angularModule(module);
13696           runBlocks = runBlocks.concat(loadModules(moduleFn.requires)).concat(moduleFn._runBlocks);
13697           runInvokeQueue(moduleFn._invokeQueue);
13698           runInvokeQueue(moduleFn._configBlocks);
13699         } else if (isFunction(module)) {
13700             runBlocks.push(providerInjector.invoke(module));
13701         } else if (isArray(module)) {
13702             runBlocks.push(providerInjector.invoke(module));
13703         } else {
13704           assertArgFn(module, 'module');
13705         }
13706       } catch (e) {
13707         if (isArray(module)) {
13708           module = module[module.length - 1];
13709         }
13710         if (e.message && e.stack && e.stack.indexOf(e.message) == -1) {
13711           // Safari & FF's stack traces don't contain error.message content
13712           // unlike those of Chrome and IE
13713           // So if stack doesn't contain message, we create a new string that contains both.
13714           // Since error.stack is read-only in Safari, I'm overriding e and not e.stack here.
13715           /* jshint -W022 */
13716           e = e.message + '\n' + e.stack;
13717         }
13718         throw $injectorMinErr('modulerr', "Failed to instantiate module {0} due to:\n{1}",
13719                   module, e.stack || e.message || e);
13720       }
13721     });
13722     return runBlocks;
13723   }
13724
13725   ////////////////////////////////////
13726   // internal Injector
13727   ////////////////////////////////////
13728
13729   function createInternalInjector(cache, factory) {
13730
13731     function getService(serviceName, caller) {
13732       if (cache.hasOwnProperty(serviceName)) {
13733         if (cache[serviceName] === INSTANTIATING) {
13734           throw $injectorMinErr('cdep', 'Circular dependency found: {0}',
13735                     serviceName + ' <- ' + path.join(' <- '));
13736         }
13737         return cache[serviceName];
13738       } else {
13739         try {
13740           path.unshift(serviceName);
13741           cache[serviceName] = INSTANTIATING;
13742           return cache[serviceName] = factory(serviceName, caller);
13743         } catch (err) {
13744           if (cache[serviceName] === INSTANTIATING) {
13745             delete cache[serviceName];
13746           }
13747           throw err;
13748         } finally {
13749           path.shift();
13750         }
13751       }
13752     }
13753
13754
13755     function injectionArgs(fn, locals, serviceName) {
13756       var args = [],
13757           $inject = createInjector.$$annotate(fn, strictDi, serviceName);
13758
13759       for (var i = 0, length = $inject.length; i < length; i++) {
13760         var key = $inject[i];
13761         if (typeof key !== 'string') {
13762           throw $injectorMinErr('itkn',
13763                   'Incorrect injection token! Expected service name as string, got {0}', key);
13764         }
13765         args.push(locals && locals.hasOwnProperty(key) ? locals[key] :
13766                                                          getService(key, serviceName));
13767       }
13768       return args;
13769     }
13770
13771     function isClass(func) {
13772       // IE 9-11 do not support classes and IE9 leaks with the code below.
13773       if (msie <= 11) {
13774         return false;
13775       }
13776       // Workaround for MS Edge.
13777       // Check https://connect.microsoft.com/IE/Feedback/Details/2211653
13778       return typeof func === 'function'
13779         && /^(?:class\s|constructor\()/.test(Function.prototype.toString.call(func));
13780     }
13781
13782     function invoke(fn, self, locals, serviceName) {
13783       if (typeof locals === 'string') {
13784         serviceName = locals;
13785         locals = null;
13786       }
13787
13788       var args = injectionArgs(fn, locals, serviceName);
13789       if (isArray(fn)) {
13790         fn = fn[fn.length - 1];
13791       }
13792
13793       if (!isClass(fn)) {
13794         // http://jsperf.com/angularjs-invoke-apply-vs-switch
13795         // #5388
13796         return fn.apply(self, args);
13797       } else {
13798         args.unshift(null);
13799         return new (Function.prototype.bind.apply(fn, args))();
13800       }
13801     }
13802
13803
13804     function instantiate(Type, locals, serviceName) {
13805       // Check if Type is annotated and use just the given function at n-1 as parameter
13806       // e.g. someModule.factory('greeter', ['$window', function(renamed$window) {}]);
13807       var ctor = (isArray(Type) ? Type[Type.length - 1] : Type);
13808       var args = injectionArgs(Type, locals, serviceName);
13809       // Empty object at position 0 is ignored for invocation with `new`, but required.
13810       args.unshift(null);
13811       return new (Function.prototype.bind.apply(ctor, args))();
13812     }
13813
13814
13815     return {
13816       invoke: invoke,
13817       instantiate: instantiate,
13818       get: getService,
13819       annotate: createInjector.$$annotate,
13820       has: function(name) {
13821         return providerCache.hasOwnProperty(name + providerSuffix) || cache.hasOwnProperty(name);
13822       }
13823     };
13824   }
13825 }
13826
13827 createInjector.$$annotate = annotate;
13828
13829 /**
13830  * @ngdoc provider
13831  * @name $anchorScrollProvider
13832  *
13833  * @description
13834  * Use `$anchorScrollProvider` to disable automatic scrolling whenever
13835  * {@link ng.$location#hash $location.hash()} changes.
13836  */
13837 function $AnchorScrollProvider() {
13838
13839   var autoScrollingEnabled = true;
13840
13841   /**
13842    * @ngdoc method
13843    * @name $anchorScrollProvider#disableAutoScrolling
13844    *
13845    * @description
13846    * By default, {@link ng.$anchorScroll $anchorScroll()} will automatically detect changes to
13847    * {@link ng.$location#hash $location.hash()} and scroll to the element matching the new hash.<br />
13848    * Use this method to disable automatic scrolling.
13849    *
13850    * If automatic scrolling is disabled, one must explicitly call
13851    * {@link ng.$anchorScroll $anchorScroll()} in order to scroll to the element related to the
13852    * current hash.
13853    */
13854   this.disableAutoScrolling = function() {
13855     autoScrollingEnabled = false;
13856   };
13857
13858   /**
13859    * @ngdoc service
13860    * @name $anchorScroll
13861    * @kind function
13862    * @requires $window
13863    * @requires $location
13864    * @requires $rootScope
13865    *
13866    * @description
13867    * When called, it scrolls to the element related to the specified `hash` or (if omitted) to the
13868    * current value of {@link ng.$location#hash $location.hash()}, according to the rules specified
13869    * in the
13870    * [HTML5 spec](http://www.w3.org/html/wg/drafts/html/master/browsers.html#the-indicated-part-of-the-document).
13871    *
13872    * It also watches the {@link ng.$location#hash $location.hash()} and automatically scrolls to
13873    * match any anchor whenever it changes. This can be disabled by calling
13874    * {@link ng.$anchorScrollProvider#disableAutoScrolling $anchorScrollProvider.disableAutoScrolling()}.
13875    *
13876    * Additionally, you can use its {@link ng.$anchorScroll#yOffset yOffset} property to specify a
13877    * vertical scroll-offset (either fixed or dynamic).
13878    *
13879    * @param {string=} hash The hash specifying the element to scroll to. If omitted, the value of
13880    *                       {@link ng.$location#hash $location.hash()} will be used.
13881    *
13882    * @property {(number|function|jqLite)} yOffset
13883    * If set, specifies a vertical scroll-offset. This is often useful when there are fixed
13884    * positioned elements at the top of the page, such as navbars, headers etc.
13885    *
13886    * `yOffset` can be specified in various ways:
13887    * - **number**: A fixed number of pixels to be used as offset.<br /><br />
13888    * - **function**: A getter function called everytime `$anchorScroll()` is executed. Must return
13889    *   a number representing the offset (in pixels).<br /><br />
13890    * - **jqLite**: A jqLite/jQuery element to be used for specifying the offset. The distance from
13891    *   the top of the page to the element's bottom will be used as offset.<br />
13892    *   **Note**: The element will be taken into account only as long as its `position` is set to
13893    *   `fixed`. This option is useful, when dealing with responsive navbars/headers that adjust
13894    *   their height and/or positioning according to the viewport's size.
13895    *
13896    * <br />
13897    * <div class="alert alert-warning">
13898    * In order for `yOffset` to work properly, scrolling should take place on the document's root and
13899    * not some child element.
13900    * </div>
13901    *
13902    * @example
13903      <example module="anchorScrollExample">
13904        <file name="index.html">
13905          <div id="scrollArea" ng-controller="ScrollController">
13906            <a ng-click="gotoBottom()">Go to bottom</a>
13907            <a id="bottom"></a> You're at the bottom!
13908          </div>
13909        </file>
13910        <file name="script.js">
13911          angular.module('anchorScrollExample', [])
13912            .controller('ScrollController', ['$scope', '$location', '$anchorScroll',
13913              function ($scope, $location, $anchorScroll) {
13914                $scope.gotoBottom = function() {
13915                  // set the location.hash to the id of
13916                  // the element you wish to scroll to.
13917                  $location.hash('bottom');
13918
13919                  // call $anchorScroll()
13920                  $anchorScroll();
13921                };
13922              }]);
13923        </file>
13924        <file name="style.css">
13925          #scrollArea {
13926            height: 280px;
13927            overflow: auto;
13928          }
13929
13930          #bottom {
13931            display: block;
13932            margin-top: 2000px;
13933          }
13934        </file>
13935      </example>
13936    *
13937    * <hr />
13938    * The example below illustrates the use of a vertical scroll-offset (specified as a fixed value).
13939    * See {@link ng.$anchorScroll#yOffset $anchorScroll.yOffset} for more details.
13940    *
13941    * @example
13942      <example module="anchorScrollOffsetExample">
13943        <file name="index.html">
13944          <div class="fixed-header" ng-controller="headerCtrl">
13945            <a href="" ng-click="gotoAnchor(x)" ng-repeat="x in [1,2,3,4,5]">
13946              Go to anchor {{x}}
13947            </a>
13948          </div>
13949          <div id="anchor{{x}}" class="anchor" ng-repeat="x in [1,2,3,4,5]">
13950            Anchor {{x}} of 5
13951          </div>
13952        </file>
13953        <file name="script.js">
13954          angular.module('anchorScrollOffsetExample', [])
13955            .run(['$anchorScroll', function($anchorScroll) {
13956              $anchorScroll.yOffset = 50;   // always scroll by 50 extra pixels
13957            }])
13958            .controller('headerCtrl', ['$anchorScroll', '$location', '$scope',
13959              function ($anchorScroll, $location, $scope) {
13960                $scope.gotoAnchor = function(x) {
13961                  var newHash = 'anchor' + x;
13962                  if ($location.hash() !== newHash) {
13963                    // set the $location.hash to `newHash` and
13964                    // $anchorScroll will automatically scroll to it
13965                    $location.hash('anchor' + x);
13966                  } else {
13967                    // call $anchorScroll() explicitly,
13968                    // since $location.hash hasn't changed
13969                    $anchorScroll();
13970                  }
13971                };
13972              }
13973            ]);
13974        </file>
13975        <file name="style.css">
13976          body {
13977            padding-top: 50px;
13978          }
13979
13980          .anchor {
13981            border: 2px dashed DarkOrchid;
13982            padding: 10px 10px 200px 10px;
13983          }
13984
13985          .fixed-header {
13986            background-color: rgba(0, 0, 0, 0.2);
13987            height: 50px;
13988            position: fixed;
13989            top: 0; left: 0; right: 0;
13990          }
13991
13992          .fixed-header > a {
13993            display: inline-block;
13994            margin: 5px 15px;
13995          }
13996        </file>
13997      </example>
13998    */
13999   this.$get = ['$window', '$location', '$rootScope', function($window, $location, $rootScope) {
14000     var document = $window.document;
14001
14002     // Helper function to get first anchor from a NodeList
14003     // (using `Array#some()` instead of `angular#forEach()` since it's more performant
14004     //  and working in all supported browsers.)
14005     function getFirstAnchor(list) {
14006       var result = null;
14007       Array.prototype.some.call(list, function(element) {
14008         if (nodeName_(element) === 'a') {
14009           result = element;
14010           return true;
14011         }
14012       });
14013       return result;
14014     }
14015
14016     function getYOffset() {
14017
14018       var offset = scroll.yOffset;
14019
14020       if (isFunction(offset)) {
14021         offset = offset();
14022       } else if (isElement(offset)) {
14023         var elem = offset[0];
14024         var style = $window.getComputedStyle(elem);
14025         if (style.position !== 'fixed') {
14026           offset = 0;
14027         } else {
14028           offset = elem.getBoundingClientRect().bottom;
14029         }
14030       } else if (!isNumber(offset)) {
14031         offset = 0;
14032       }
14033
14034       return offset;
14035     }
14036
14037     function scrollTo(elem) {
14038       if (elem) {
14039         elem.scrollIntoView();
14040
14041         var offset = getYOffset();
14042
14043         if (offset) {
14044           // `offset` is the number of pixels we should scroll UP in order to align `elem` properly.
14045           // This is true ONLY if the call to `elem.scrollIntoView()` initially aligns `elem` at the
14046           // top of the viewport.
14047           //
14048           // IF the number of pixels from the top of `elem` to the end of the page's content is less
14049           // than the height of the viewport, then `elem.scrollIntoView()` will align the `elem` some
14050           // way down the page.
14051           //
14052           // This is often the case for elements near the bottom of the page.
14053           //
14054           // In such cases we do not need to scroll the whole `offset` up, just the difference between
14055           // the top of the element and the offset, which is enough to align the top of `elem` at the
14056           // desired position.
14057           var elemTop = elem.getBoundingClientRect().top;
14058           $window.scrollBy(0, elemTop - offset);
14059         }
14060       } else {
14061         $window.scrollTo(0, 0);
14062       }
14063     }
14064
14065     function scroll(hash) {
14066       hash = isString(hash) ? hash : $location.hash();
14067       var elm;
14068
14069       // empty hash, scroll to the top of the page
14070       if (!hash) scrollTo(null);
14071
14072       // element with given id
14073       else if ((elm = document.getElementById(hash))) scrollTo(elm);
14074
14075       // first anchor with given name :-D
14076       else if ((elm = getFirstAnchor(document.getElementsByName(hash)))) scrollTo(elm);
14077
14078       // no element and hash == 'top', scroll to the top of the page
14079       else if (hash === 'top') scrollTo(null);
14080     }
14081
14082     // does not scroll when user clicks on anchor link that is currently on
14083     // (no url change, no $location.hash() change), browser native does scroll
14084     if (autoScrollingEnabled) {
14085       $rootScope.$watch(function autoScrollWatch() {return $location.hash();},
14086         function autoScrollWatchAction(newVal, oldVal) {
14087           // skip the initial scroll if $location.hash is empty
14088           if (newVal === oldVal && newVal === '') return;
14089
14090           jqLiteDocumentLoaded(function() {
14091             $rootScope.$evalAsync(scroll);
14092           });
14093         });
14094     }
14095
14096     return scroll;
14097   }];
14098 }
14099
14100 var $animateMinErr = minErr('$animate');
14101 var ELEMENT_NODE = 1;
14102 var NG_ANIMATE_CLASSNAME = 'ng-animate';
14103
14104 function mergeClasses(a,b) {
14105   if (!a && !b) return '';
14106   if (!a) return b;
14107   if (!b) return a;
14108   if (isArray(a)) a = a.join(' ');
14109   if (isArray(b)) b = b.join(' ');
14110   return a + ' ' + b;
14111 }
14112
14113 function extractElementNode(element) {
14114   for (var i = 0; i < element.length; i++) {
14115     var elm = element[i];
14116     if (elm.nodeType === ELEMENT_NODE) {
14117       return elm;
14118     }
14119   }
14120 }
14121
14122 function splitClasses(classes) {
14123   if (isString(classes)) {
14124     classes = classes.split(' ');
14125   }
14126
14127   // Use createMap() to prevent class assumptions involving property names in
14128   // Object.prototype
14129   var obj = createMap();
14130   forEach(classes, function(klass) {
14131     // sometimes the split leaves empty string values
14132     // incase extra spaces were applied to the options
14133     if (klass.length) {
14134       obj[klass] = true;
14135     }
14136   });
14137   return obj;
14138 }
14139
14140 // if any other type of options value besides an Object value is
14141 // passed into the $animate.method() animation then this helper code
14142 // will be run which will ignore it. While this patch is not the
14143 // greatest solution to this, a lot of existing plugins depend on
14144 // $animate to either call the callback (< 1.2) or return a promise
14145 // that can be changed. This helper function ensures that the options
14146 // are wiped clean incase a callback function is provided.
14147 function prepareAnimateOptions(options) {
14148   return isObject(options)
14149       ? options
14150       : {};
14151 }
14152
14153 var $$CoreAnimateJsProvider = function() {
14154   this.$get = function() {};
14155 };
14156
14157 // this is prefixed with Core since it conflicts with
14158 // the animateQueueProvider defined in ngAnimate/animateQueue.js
14159 var $$CoreAnimateQueueProvider = function() {
14160   var postDigestQueue = new HashMap();
14161   var postDigestElements = [];
14162
14163   this.$get = ['$$AnimateRunner', '$rootScope',
14164        function($$AnimateRunner,   $rootScope) {
14165     return {
14166       enabled: noop,
14167       on: noop,
14168       off: noop,
14169       pin: noop,
14170
14171       push: function(element, event, options, domOperation) {
14172         domOperation        && domOperation();
14173
14174         options = options || {};
14175         options.from        && element.css(options.from);
14176         options.to          && element.css(options.to);
14177
14178         if (options.addClass || options.removeClass) {
14179           addRemoveClassesPostDigest(element, options.addClass, options.removeClass);
14180         }
14181
14182         var runner = new $$AnimateRunner(); // jshint ignore:line
14183
14184         // since there are no animations to run the runner needs to be
14185         // notified that the animation call is complete.
14186         runner.complete();
14187         return runner;
14188       }
14189     };
14190
14191
14192     function updateData(data, classes, value) {
14193       var changed = false;
14194       if (classes) {
14195         classes = isString(classes) ? classes.split(' ') :
14196                   isArray(classes) ? classes : [];
14197         forEach(classes, function(className) {
14198           if (className) {
14199             changed = true;
14200             data[className] = value;
14201           }
14202         });
14203       }
14204       return changed;
14205     }
14206
14207     function handleCSSClassChanges() {
14208       forEach(postDigestElements, function(element) {
14209         var data = postDigestQueue.get(element);
14210         if (data) {
14211           var existing = splitClasses(element.attr('class'));
14212           var toAdd = '';
14213           var toRemove = '';
14214           forEach(data, function(status, className) {
14215             var hasClass = !!existing[className];
14216             if (status !== hasClass) {
14217               if (status) {
14218                 toAdd += (toAdd.length ? ' ' : '') + className;
14219               } else {
14220                 toRemove += (toRemove.length ? ' ' : '') + className;
14221               }
14222             }
14223           });
14224
14225           forEach(element, function(elm) {
14226             toAdd    && jqLiteAddClass(elm, toAdd);
14227             toRemove && jqLiteRemoveClass(elm, toRemove);
14228           });
14229           postDigestQueue.remove(element);
14230         }
14231       });
14232       postDigestElements.length = 0;
14233     }
14234
14235
14236     function addRemoveClassesPostDigest(element, add, remove) {
14237       var data = postDigestQueue.get(element) || {};
14238
14239       var classesAdded = updateData(data, add, true);
14240       var classesRemoved = updateData(data, remove, false);
14241
14242       if (classesAdded || classesRemoved) {
14243
14244         postDigestQueue.put(element, data);
14245         postDigestElements.push(element);
14246
14247         if (postDigestElements.length === 1) {
14248           $rootScope.$$postDigest(handleCSSClassChanges);
14249         }
14250       }
14251     }
14252   }];
14253 };
14254
14255 /**
14256  * @ngdoc provider
14257  * @name $animateProvider
14258  *
14259  * @description
14260  * Default implementation of $animate that doesn't perform any animations, instead just
14261  * synchronously performs DOM updates and resolves the returned runner promise.
14262  *
14263  * In order to enable animations the `ngAnimate` module has to be loaded.
14264  *
14265  * To see the functional implementation check out `src/ngAnimate/animate.js`.
14266  */
14267 var $AnimateProvider = ['$provide', function($provide) {
14268   var provider = this;
14269
14270   this.$$registeredAnimations = Object.create(null);
14271
14272    /**
14273    * @ngdoc method
14274    * @name $animateProvider#register
14275    *
14276    * @description
14277    * Registers a new injectable animation factory function. The factory function produces the
14278    * animation object which contains callback functions for each event that is expected to be
14279    * animated.
14280    *
14281    *   * `eventFn`: `function(element, ... , doneFunction, options)`
14282    *   The element to animate, the `doneFunction` and the options fed into the animation. Depending
14283    *   on the type of animation additional arguments will be injected into the animation function. The
14284    *   list below explains the function signatures for the different animation methods:
14285    *
14286    *   - setClass: function(element, addedClasses, removedClasses, doneFunction, options)
14287    *   - addClass: function(element, addedClasses, doneFunction, options)
14288    *   - removeClass: function(element, removedClasses, doneFunction, options)
14289    *   - enter, leave, move: function(element, doneFunction, options)
14290    *   - animate: function(element, fromStyles, toStyles, doneFunction, options)
14291    *
14292    *   Make sure to trigger the `doneFunction` once the animation is fully complete.
14293    *
14294    * ```js
14295    *   return {
14296    *     //enter, leave, move signature
14297    *     eventFn : function(element, done, options) {
14298    *       //code to run the animation
14299    *       //once complete, then run done()
14300    *       return function endFunction(wasCancelled) {
14301    *         //code to cancel the animation
14302    *       }
14303    *     }
14304    *   }
14305    * ```
14306    *
14307    * @param {string} name The name of the animation (this is what the class-based CSS value will be compared to).
14308    * @param {Function} factory The factory function that will be executed to return the animation
14309    *                           object.
14310    */
14311   this.register = function(name, factory) {
14312     if (name && name.charAt(0) !== '.') {
14313       throw $animateMinErr('notcsel', "Expecting class selector starting with '.' got '{0}'.", name);
14314     }
14315
14316     var key = name + '-animation';
14317     provider.$$registeredAnimations[name.substr(1)] = key;
14318     $provide.factory(key, factory);
14319   };
14320
14321   /**
14322    * @ngdoc method
14323    * @name $animateProvider#classNameFilter
14324    *
14325    * @description
14326    * Sets and/or returns the CSS class regular expression that is checked when performing
14327    * an animation. Upon bootstrap the classNameFilter value is not set at all and will
14328    * therefore enable $animate to attempt to perform an animation on any element that is triggered.
14329    * When setting the `classNameFilter` value, animations will only be performed on elements
14330    * that successfully match the filter expression. This in turn can boost performance
14331    * for low-powered devices as well as applications containing a lot of structural operations.
14332    * @param {RegExp=} expression The className expression which will be checked against all animations
14333    * @return {RegExp} The current CSS className expression value. If null then there is no expression value
14334    */
14335   this.classNameFilter = function(expression) {
14336     if (arguments.length === 1) {
14337       this.$$classNameFilter = (expression instanceof RegExp) ? expression : null;
14338       if (this.$$classNameFilter) {
14339         var reservedRegex = new RegExp("(\\s+|\\/)" + NG_ANIMATE_CLASSNAME + "(\\s+|\\/)");
14340         if (reservedRegex.test(this.$$classNameFilter.toString())) {
14341           throw $animateMinErr('nongcls','$animateProvider.classNameFilter(regex) prohibits accepting a regex value which matches/contains the "{0}" CSS class.', NG_ANIMATE_CLASSNAME);
14342
14343         }
14344       }
14345     }
14346     return this.$$classNameFilter;
14347   };
14348
14349   this.$get = ['$$animateQueue', function($$animateQueue) {
14350     function domInsert(element, parentElement, afterElement) {
14351       // if for some reason the previous element was removed
14352       // from the dom sometime before this code runs then let's
14353       // just stick to using the parent element as the anchor
14354       if (afterElement) {
14355         var afterNode = extractElementNode(afterElement);
14356         if (afterNode && !afterNode.parentNode && !afterNode.previousElementSibling) {
14357           afterElement = null;
14358         }
14359       }
14360       afterElement ? afterElement.after(element) : parentElement.prepend(element);
14361     }
14362
14363     /**
14364      * @ngdoc service
14365      * @name $animate
14366      * @description The $animate service exposes a series of DOM utility methods that provide support
14367      * for animation hooks. The default behavior is the application of DOM operations, however,
14368      * when an animation is detected (and animations are enabled), $animate will do the heavy lifting
14369      * to ensure that animation runs with the triggered DOM operation.
14370      *
14371      * By default $animate doesn't trigger any animations. This is because the `ngAnimate` module isn't
14372      * included and only when it is active then the animation hooks that `$animate` triggers will be
14373      * functional. Once active then all structural `ng-` directives will trigger animations as they perform
14374      * their DOM-related operations (enter, leave and move). Other directives such as `ngClass`,
14375      * `ngShow`, `ngHide` and `ngMessages` also provide support for animations.
14376      *
14377      * It is recommended that the`$animate` service is always used when executing DOM-related procedures within directives.
14378      *
14379      * To learn more about enabling animation support, click here to visit the
14380      * {@link ngAnimate ngAnimate module page}.
14381      */
14382     return {
14383       // we don't call it directly since non-existant arguments may
14384       // be interpreted as null within the sub enabled function
14385
14386       /**
14387        *
14388        * @ngdoc method
14389        * @name $animate#on
14390        * @kind function
14391        * @description Sets up an event listener to fire whenever the animation event (enter, leave, move, etc...)
14392        *    has fired on the given element or among any of its children. Once the listener is fired, the provided callback
14393        *    is fired with the following params:
14394        *
14395        * ```js
14396        * $animate.on('enter', container,
14397        *    function callback(element, phase) {
14398        *      // cool we detected an enter animation within the container
14399        *    }
14400        * );
14401        * ```
14402        *
14403        * @param {string} event the animation event that will be captured (e.g. enter, leave, move, addClass, removeClass, etc...)
14404        * @param {DOMElement} container the container element that will capture each of the animation events that are fired on itself
14405        *     as well as among its children
14406        * @param {Function} callback the callback function that will be fired when the listener is triggered
14407        *
14408        * The arguments present in the callback function are:
14409        * * `element` - The captured DOM element that the animation was fired on.
14410        * * `phase` - The phase of the animation. The two possible phases are **start** (when the animation starts) and **close** (when it ends).
14411        */
14412       on: $$animateQueue.on,
14413
14414       /**
14415        *
14416        * @ngdoc method
14417        * @name $animate#off
14418        * @kind function
14419        * @description Deregisters an event listener based on the event which has been associated with the provided element. This method
14420        * can be used in three different ways depending on the arguments:
14421        *
14422        * ```js
14423        * // remove all the animation event listeners listening for `enter`
14424        * $animate.off('enter');
14425        *
14426        * // remove all the animation event listeners listening for `enter` on the given element and its children
14427        * $animate.off('enter', container);
14428        *
14429        * // remove the event listener function provided by `callback` that is set
14430        * // to listen for `enter` on the given `container` as well as its children
14431        * $animate.off('enter', container, callback);
14432        * ```
14433        *
14434        * @param {string} event the animation event (e.g. enter, leave, move, addClass, removeClass, etc...)
14435        * @param {DOMElement=} container the container element the event listener was placed on
14436        * @param {Function=} callback the callback function that was registered as the listener
14437        */
14438       off: $$animateQueue.off,
14439
14440       /**
14441        * @ngdoc method
14442        * @name $animate#pin
14443        * @kind function
14444        * @description Associates the provided element with a host parent element to allow the element to be animated even if it exists
14445        *    outside of the DOM structure of the Angular application. By doing so, any animation triggered via `$animate` can be issued on the
14446        *    element despite being outside the realm of the application or within another application. Say for example if the application
14447        *    was bootstrapped on an element that is somewhere inside of the `<body>` tag, but we wanted to allow for an element to be situated
14448        *    as a direct child of `document.body`, then this can be achieved by pinning the element via `$animate.pin(element)`. Keep in mind
14449        *    that calling `$animate.pin(element, parentElement)` will not actually insert into the DOM anywhere; it will just create the association.
14450        *
14451        *    Note that this feature is only active when the `ngAnimate` module is used.
14452        *
14453        * @param {DOMElement} element the external element that will be pinned
14454        * @param {DOMElement} parentElement the host parent element that will be associated with the external element
14455        */
14456       pin: $$animateQueue.pin,
14457
14458       /**
14459        *
14460        * @ngdoc method
14461        * @name $animate#enabled
14462        * @kind function
14463        * @description Used to get and set whether animations are enabled or not on the entire application or on an element and its children. This
14464        * function can be called in four ways:
14465        *
14466        * ```js
14467        * // returns true or false
14468        * $animate.enabled();
14469        *
14470        * // changes the enabled state for all animations
14471        * $animate.enabled(false);
14472        * $animate.enabled(true);
14473        *
14474        * // returns true or false if animations are enabled for an element
14475        * $animate.enabled(element);
14476        *
14477        * // changes the enabled state for an element and its children
14478        * $animate.enabled(element, true);
14479        * $animate.enabled(element, false);
14480        * ```
14481        *
14482        * @param {DOMElement=} element the element that will be considered for checking/setting the enabled state
14483        * @param {boolean=} enabled whether or not the animations will be enabled for the element
14484        *
14485        * @return {boolean} whether or not animations are enabled
14486        */
14487       enabled: $$animateQueue.enabled,
14488
14489       /**
14490        * @ngdoc method
14491        * @name $animate#cancel
14492        * @kind function
14493        * @description Cancels the provided animation.
14494        *
14495        * @param {Promise} animationPromise The animation promise that is returned when an animation is started.
14496        */
14497       cancel: function(runner) {
14498         runner.end && runner.end();
14499       },
14500
14501       /**
14502        *
14503        * @ngdoc method
14504        * @name $animate#enter
14505        * @kind function
14506        * @description Inserts the element into the DOM either after the `after` element (if provided) or
14507        *   as the first child within the `parent` element and then triggers an animation.
14508        *   A promise is returned that will be resolved during the next digest once the animation
14509        *   has completed.
14510        *
14511        * @param {DOMElement} element the element which will be inserted into the DOM
14512        * @param {DOMElement} parent the parent element which will append the element as
14513        *   a child (so long as the after element is not present)
14514        * @param {DOMElement=} after the sibling element after which the element will be appended
14515        * @param {object=} options an optional collection of options/styles that will be applied to the element
14516        *
14517        * @return {Promise} the animation callback promise
14518        */
14519       enter: function(element, parent, after, options) {
14520         parent = parent && jqLite(parent);
14521         after = after && jqLite(after);
14522         parent = parent || after.parent();
14523         domInsert(element, parent, after);
14524         return $$animateQueue.push(element, 'enter', prepareAnimateOptions(options));
14525       },
14526
14527       /**
14528        *
14529        * @ngdoc method
14530        * @name $animate#move
14531        * @kind function
14532        * @description Inserts (moves) the element into its new position in the DOM either after
14533        *   the `after` element (if provided) or as the first child within the `parent` element
14534        *   and then triggers an animation. A promise is returned that will be resolved
14535        *   during the next digest once the animation has completed.
14536        *
14537        * @param {DOMElement} element the element which will be moved into the new DOM position
14538        * @param {DOMElement} parent the parent element which will append the element as
14539        *   a child (so long as the after element is not present)
14540        * @param {DOMElement=} after the sibling element after which the element will be appended
14541        * @param {object=} options an optional collection of options/styles that will be applied to the element
14542        *
14543        * @return {Promise} the animation callback promise
14544        */
14545       move: function(element, parent, after, options) {
14546         parent = parent && jqLite(parent);
14547         after = after && jqLite(after);
14548         parent = parent || after.parent();
14549         domInsert(element, parent, after);
14550         return $$animateQueue.push(element, 'move', prepareAnimateOptions(options));
14551       },
14552
14553       /**
14554        * @ngdoc method
14555        * @name $animate#leave
14556        * @kind function
14557        * @description Triggers an animation and then removes the element from the DOM.
14558        * When the function is called a promise is returned that will be resolved during the next
14559        * digest once the animation has completed.
14560        *
14561        * @param {DOMElement} element the element which will be removed from the DOM
14562        * @param {object=} options an optional collection of options/styles that will be applied to the element
14563        *
14564        * @return {Promise} the animation callback promise
14565        */
14566       leave: function(element, options) {
14567         return $$animateQueue.push(element, 'leave', prepareAnimateOptions(options), function() {
14568           element.remove();
14569         });
14570       },
14571
14572       /**
14573        * @ngdoc method
14574        * @name $animate#addClass
14575        * @kind function
14576        *
14577        * @description Triggers an addClass animation surrounding the addition of the provided CSS class(es). Upon
14578        *   execution, the addClass operation will only be handled after the next digest and it will not trigger an
14579        *   animation if element already contains the CSS class or if the class is removed at a later step.
14580        *   Note that class-based animations are treated differently compared to structural animations
14581        *   (like enter, move and leave) since the CSS classes may be added/removed at different points
14582        *   depending if CSS or JavaScript animations are used.
14583        *
14584        * @param {DOMElement} element the element which the CSS classes will be applied to
14585        * @param {string} className the CSS class(es) that will be added (multiple classes are separated via spaces)
14586        * @param {object=} options an optional collection of options/styles that will be applied to the element
14587        *
14588        * @return {Promise} the animation callback promise
14589        */
14590       addClass: function(element, className, options) {
14591         options = prepareAnimateOptions(options);
14592         options.addClass = mergeClasses(options.addclass, className);
14593         return $$animateQueue.push(element, 'addClass', options);
14594       },
14595
14596       /**
14597        * @ngdoc method
14598        * @name $animate#removeClass
14599        * @kind function
14600        *
14601        * @description Triggers a removeClass animation surrounding the removal of the provided CSS class(es). Upon
14602        *   execution, the removeClass operation will only be handled after the next digest and it will not trigger an
14603        *   animation if element does not contain the CSS class or if the class is added at a later step.
14604        *   Note that class-based animations are treated differently compared to structural animations
14605        *   (like enter, move and leave) since the CSS classes may be added/removed at different points
14606        *   depending if CSS or JavaScript animations are used.
14607        *
14608        * @param {DOMElement} element the element which the CSS classes will be applied to
14609        * @param {string} className the CSS class(es) that will be removed (multiple classes are separated via spaces)
14610        * @param {object=} options an optional collection of options/styles that will be applied to the element
14611        *
14612        * @return {Promise} the animation callback promise
14613        */
14614       removeClass: function(element, className, options) {
14615         options = prepareAnimateOptions(options);
14616         options.removeClass = mergeClasses(options.removeClass, className);
14617         return $$animateQueue.push(element, 'removeClass', options);
14618       },
14619
14620       /**
14621        * @ngdoc method
14622        * @name $animate#setClass
14623        * @kind function
14624        *
14625        * @description Performs both the addition and removal of a CSS classes on an element and (during the process)
14626        *    triggers an animation surrounding the class addition/removal. Much like `$animate.addClass` and
14627        *    `$animate.removeClass`, `setClass` will only evaluate the classes being added/removed once a digest has
14628        *    passed. Note that class-based animations are treated differently compared to structural animations
14629        *    (like enter, move and leave) since the CSS classes may be added/removed at different points
14630        *    depending if CSS or JavaScript animations are used.
14631        *
14632        * @param {DOMElement} element the element which the CSS classes will be applied to
14633        * @param {string} add the CSS class(es) that will be added (multiple classes are separated via spaces)
14634        * @param {string} remove the CSS class(es) that will be removed (multiple classes are separated via spaces)
14635        * @param {object=} options an optional collection of options/styles that will be applied to the element
14636        *
14637        * @return {Promise} the animation callback promise
14638        */
14639       setClass: function(element, add, remove, options) {
14640         options = prepareAnimateOptions(options);
14641         options.addClass = mergeClasses(options.addClass, add);
14642         options.removeClass = mergeClasses(options.removeClass, remove);
14643         return $$animateQueue.push(element, 'setClass', options);
14644       },
14645
14646       /**
14647        * @ngdoc method
14648        * @name $animate#animate
14649        * @kind function
14650        *
14651        * @description Performs an inline animation on the element which applies the provided to and from CSS styles to the element.
14652        * If any detected CSS transition, keyframe or JavaScript matches the provided className value, then the animation will take
14653        * on the provided styles. For example, if a transition animation is set for the given classNamem, then the provided `from` and
14654        * `to` styles will be applied alongside the given transition. If the CSS style provided in `from` does not have a corresponding
14655        * style in `to`, the style in `from` is applied immediately, and no animation is run.
14656        * If a JavaScript animation is detected then the provided styles will be given in as function parameters into the `animate`
14657        * method (or as part of the `options` parameter):
14658        *
14659        * ```js
14660        * ngModule.animation('.my-inline-animation', function() {
14661        *   return {
14662        *     animate : function(element, from, to, done, options) {
14663        *       //animation
14664        *       done();
14665        *     }
14666        *   }
14667        * });
14668        * ```
14669        *
14670        * @param {DOMElement} element the element which the CSS styles will be applied to
14671        * @param {object} from the from (starting) CSS styles that will be applied to the element and across the animation.
14672        * @param {object} to the to (destination) CSS styles that will be applied to the element and across the animation.
14673        * @param {string=} className an optional CSS class that will be applied to the element for the duration of the animation. If
14674        *    this value is left as empty then a CSS class of `ng-inline-animate` will be applied to the element.
14675        *    (Note that if no animation is detected then this value will not be applied to the element.)
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       animate: function(element, from, to, className, options) {
14681         options = prepareAnimateOptions(options);
14682         options.from = options.from ? extend(options.from, from) : from;
14683         options.to   = options.to   ? extend(options.to, to)     : to;
14684
14685         className = className || 'ng-inline-animate';
14686         options.tempClasses = mergeClasses(options.tempClasses, className);
14687         return $$animateQueue.push(element, 'animate', options);
14688       }
14689     };
14690   }];
14691 }];
14692
14693 var $$AnimateAsyncRunFactoryProvider = function() {
14694   this.$get = ['$$rAF', function($$rAF) {
14695     var waitQueue = [];
14696
14697     function waitForTick(fn) {
14698       waitQueue.push(fn);
14699       if (waitQueue.length > 1) return;
14700       $$rAF(function() {
14701         for (var i = 0; i < waitQueue.length; i++) {
14702           waitQueue[i]();
14703         }
14704         waitQueue = [];
14705       });
14706     }
14707
14708     return function() {
14709       var passed = false;
14710       waitForTick(function() {
14711         passed = true;
14712       });
14713       return function(callback) {
14714         passed ? callback() : waitForTick(callback);
14715       };
14716     };
14717   }];
14718 };
14719
14720 var $$AnimateRunnerFactoryProvider = function() {
14721   this.$get = ['$q', '$sniffer', '$$animateAsyncRun', '$document', '$timeout',
14722        function($q,   $sniffer,   $$animateAsyncRun,   $document,   $timeout) {
14723
14724     var INITIAL_STATE = 0;
14725     var DONE_PENDING_STATE = 1;
14726     var DONE_COMPLETE_STATE = 2;
14727
14728     AnimateRunner.chain = function(chain, callback) {
14729       var index = 0;
14730
14731       next();
14732       function next() {
14733         if (index === chain.length) {
14734           callback(true);
14735           return;
14736         }
14737
14738         chain[index](function(response) {
14739           if (response === false) {
14740             callback(false);
14741             return;
14742           }
14743           index++;
14744           next();
14745         });
14746       }
14747     };
14748
14749     AnimateRunner.all = function(runners, callback) {
14750       var count = 0;
14751       var status = true;
14752       forEach(runners, function(runner) {
14753         runner.done(onProgress);
14754       });
14755
14756       function onProgress(response) {
14757         status = status && response;
14758         if (++count === runners.length) {
14759           callback(status);
14760         }
14761       }
14762     };
14763
14764     function AnimateRunner(host) {
14765       this.setHost(host);
14766
14767       var rafTick = $$animateAsyncRun();
14768       var timeoutTick = function(fn) {
14769         $timeout(fn, 0, false);
14770       };
14771
14772       this._doneCallbacks = [];
14773       this._tick = function(fn) {
14774         var doc = $document[0];
14775
14776         // the document may not be ready or attached
14777         // to the module for some internal tests
14778         if (doc && doc.hidden) {
14779           timeoutTick(fn);
14780         } else {
14781           rafTick(fn);
14782         }
14783       };
14784       this._state = 0;
14785     }
14786
14787     AnimateRunner.prototype = {
14788       setHost: function(host) {
14789         this.host = host || {};
14790       },
14791
14792       done: function(fn) {
14793         if (this._state === DONE_COMPLETE_STATE) {
14794           fn();
14795         } else {
14796           this._doneCallbacks.push(fn);
14797         }
14798       },
14799
14800       progress: noop,
14801
14802       getPromise: function() {
14803         if (!this.promise) {
14804           var self = this;
14805           this.promise = $q(function(resolve, reject) {
14806             self.done(function(status) {
14807               status === false ? reject() : resolve();
14808             });
14809           });
14810         }
14811         return this.promise;
14812       },
14813
14814       then: function(resolveHandler, rejectHandler) {
14815         return this.getPromise().then(resolveHandler, rejectHandler);
14816       },
14817
14818       'catch': function(handler) {
14819         return this.getPromise()['catch'](handler);
14820       },
14821
14822       'finally': function(handler) {
14823         return this.getPromise()['finally'](handler);
14824       },
14825
14826       pause: function() {
14827         if (this.host.pause) {
14828           this.host.pause();
14829         }
14830       },
14831
14832       resume: function() {
14833         if (this.host.resume) {
14834           this.host.resume();
14835         }
14836       },
14837
14838       end: function() {
14839         if (this.host.end) {
14840           this.host.end();
14841         }
14842         this._resolve(true);
14843       },
14844
14845       cancel: function() {
14846         if (this.host.cancel) {
14847           this.host.cancel();
14848         }
14849         this._resolve(false);
14850       },
14851
14852       complete: function(response) {
14853         var self = this;
14854         if (self._state === INITIAL_STATE) {
14855           self._state = DONE_PENDING_STATE;
14856           self._tick(function() {
14857             self._resolve(response);
14858           });
14859         }
14860       },
14861
14862       _resolve: function(response) {
14863         if (this._state !== DONE_COMPLETE_STATE) {
14864           forEach(this._doneCallbacks, function(fn) {
14865             fn(response);
14866           });
14867           this._doneCallbacks.length = 0;
14868           this._state = DONE_COMPLETE_STATE;
14869         }
14870       }
14871     };
14872
14873     return AnimateRunner;
14874   }];
14875 };
14876
14877 /**
14878  * @ngdoc service
14879  * @name $animateCss
14880  * @kind object
14881  *
14882  * @description
14883  * This is the core version of `$animateCss`. By default, only when the `ngAnimate` is included,
14884  * then the `$animateCss` service will actually perform animations.
14885  *
14886  * Click here {@link ngAnimate.$animateCss to read the documentation for $animateCss}.
14887  */
14888 var $CoreAnimateCssProvider = function() {
14889   this.$get = ['$$rAF', '$q', '$$AnimateRunner', function($$rAF, $q, $$AnimateRunner) {
14890
14891     return function(element, initialOptions) {
14892       // all of the animation functions should create
14893       // a copy of the options data, however, if a
14894       // parent service has already created a copy then
14895       // we should stick to using that
14896       var options = initialOptions || {};
14897       if (!options.$$prepared) {
14898         options = copy(options);
14899       }
14900
14901       // there is no point in applying the styles since
14902       // there is no animation that goes on at all in
14903       // this version of $animateCss.
14904       if (options.cleanupStyles) {
14905         options.from = options.to = null;
14906       }
14907
14908       if (options.from) {
14909         element.css(options.from);
14910         options.from = null;
14911       }
14912
14913       /* jshint newcap: false */
14914       var closed, runner = new $$AnimateRunner();
14915       return {
14916         start: run,
14917         end: run
14918       };
14919
14920       function run() {
14921         $$rAF(function() {
14922           applyAnimationContents();
14923           if (!closed) {
14924             runner.complete();
14925           }
14926           closed = true;
14927         });
14928         return runner;
14929       }
14930
14931       function applyAnimationContents() {
14932         if (options.addClass) {
14933           element.addClass(options.addClass);
14934           options.addClass = null;
14935         }
14936         if (options.removeClass) {
14937           element.removeClass(options.removeClass);
14938           options.removeClass = null;
14939         }
14940         if (options.to) {
14941           element.css(options.to);
14942           options.to = null;
14943         }
14944       }
14945     };
14946   }];
14947 };
14948
14949 /* global stripHash: true */
14950
14951 /**
14952  * ! This is a private undocumented service !
14953  *
14954  * @name $browser
14955  * @requires $log
14956  * @description
14957  * This object has two goals:
14958  *
14959  * - hide all the global state in the browser caused by the window object
14960  * - abstract away all the browser specific features and inconsistencies
14961  *
14962  * For tests we provide {@link ngMock.$browser mock implementation} of the `$browser`
14963  * service, which can be used for convenient testing of the application without the interaction with
14964  * the real browser apis.
14965  */
14966 /**
14967  * @param {object} window The global window object.
14968  * @param {object} document jQuery wrapped document.
14969  * @param {object} $log window.console or an object with the same interface.
14970  * @param {object} $sniffer $sniffer service
14971  */
14972 function Browser(window, document, $log, $sniffer) {
14973   var self = this,
14974       rawDocument = document[0],
14975       location = window.location,
14976       history = window.history,
14977       setTimeout = window.setTimeout,
14978       clearTimeout = window.clearTimeout,
14979       pendingDeferIds = {};
14980
14981   self.isMock = false;
14982
14983   var outstandingRequestCount = 0;
14984   var outstandingRequestCallbacks = [];
14985
14986   // TODO(vojta): remove this temporary api
14987   self.$$completeOutstandingRequest = completeOutstandingRequest;
14988   self.$$incOutstandingRequestCount = function() { outstandingRequestCount++; };
14989
14990   /**
14991    * Executes the `fn` function(supports currying) and decrements the `outstandingRequestCallbacks`
14992    * counter. If the counter reaches 0, all the `outstandingRequestCallbacks` are executed.
14993    */
14994   function completeOutstandingRequest(fn) {
14995     try {
14996       fn.apply(null, sliceArgs(arguments, 1));
14997     } finally {
14998       outstandingRequestCount--;
14999       if (outstandingRequestCount === 0) {
15000         while (outstandingRequestCallbacks.length) {
15001           try {
15002             outstandingRequestCallbacks.pop()();
15003           } catch (e) {
15004             $log.error(e);
15005           }
15006         }
15007       }
15008     }
15009   }
15010
15011   function getHash(url) {
15012     var index = url.indexOf('#');
15013     return index === -1 ? '' : url.substr(index);
15014   }
15015
15016   /**
15017    * @private
15018    * Note: this method is used only by scenario runner
15019    * TODO(vojta): prefix this method with $$ ?
15020    * @param {function()} callback Function that will be called when no outstanding request
15021    */
15022   self.notifyWhenNoOutstandingRequests = function(callback) {
15023     if (outstandingRequestCount === 0) {
15024       callback();
15025     } else {
15026       outstandingRequestCallbacks.push(callback);
15027     }
15028   };
15029
15030   //////////////////////////////////////////////////////////////
15031   // URL API
15032   //////////////////////////////////////////////////////////////
15033
15034   var cachedState, lastHistoryState,
15035       lastBrowserUrl = location.href,
15036       baseElement = document.find('base'),
15037       pendingLocation = null;
15038
15039   cacheState();
15040   lastHistoryState = cachedState;
15041
15042   /**
15043    * @name $browser#url
15044    *
15045    * @description
15046    * GETTER:
15047    * Without any argument, this method just returns current value of location.href.
15048    *
15049    * SETTER:
15050    * With at least one argument, this method sets url to new value.
15051    * If html5 history api supported, pushState/replaceState is used, otherwise
15052    * location.href/location.replace is used.
15053    * Returns its own instance to allow chaining
15054    *
15055    * NOTE: this api is intended for use only by the $location service. Please use the
15056    * {@link ng.$location $location service} to change url.
15057    *
15058    * @param {string} url New url (when used as setter)
15059    * @param {boolean=} replace Should new url replace current history record?
15060    * @param {object=} state object to use with pushState/replaceState
15061    */
15062   self.url = function(url, replace, state) {
15063     // In modern browsers `history.state` is `null` by default; treating it separately
15064     // from `undefined` would cause `$browser.url('/foo')` to change `history.state`
15065     // to undefined via `pushState`. Instead, let's change `undefined` to `null` here.
15066     if (isUndefined(state)) {
15067       state = null;
15068     }
15069
15070     // Android Browser BFCache causes location, history reference to become stale.
15071     if (location !== window.location) location = window.location;
15072     if (history !== window.history) history = window.history;
15073
15074     // setter
15075     if (url) {
15076       var sameState = lastHistoryState === state;
15077
15078       // Don't change anything if previous and current URLs and states match. This also prevents
15079       // IE<10 from getting into redirect loop when in LocationHashbangInHtml5Url mode.
15080       // See https://github.com/angular/angular.js/commit/ffb2701
15081       if (lastBrowserUrl === url && (!$sniffer.history || sameState)) {
15082         return self;
15083       }
15084       var sameBase = lastBrowserUrl && stripHash(lastBrowserUrl) === stripHash(url);
15085       lastBrowserUrl = url;
15086       lastHistoryState = state;
15087       // Don't use history API if only the hash changed
15088       // due to a bug in IE10/IE11 which leads
15089       // to not firing a `hashchange` nor `popstate` event
15090       // in some cases (see #9143).
15091       if ($sniffer.history && (!sameBase || !sameState)) {
15092         history[replace ? 'replaceState' : 'pushState'](state, '', url);
15093         cacheState();
15094         // Do the assignment again so that those two variables are referentially identical.
15095         lastHistoryState = cachedState;
15096       } else {
15097         if (!sameBase || pendingLocation) {
15098           pendingLocation = url;
15099         }
15100         if (replace) {
15101           location.replace(url);
15102         } else if (!sameBase) {
15103           location.href = url;
15104         } else {
15105           location.hash = getHash(url);
15106         }
15107         if (location.href !== url) {
15108           pendingLocation = url;
15109         }
15110       }
15111       return self;
15112     // getter
15113     } else {
15114       // - pendingLocation is needed as browsers don't allow to read out
15115       //   the new location.href if a reload happened or if there is a bug like in iOS 9 (see
15116       //   https://openradar.appspot.com/22186109).
15117       // - the replacement is a workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=407172
15118       return pendingLocation || location.href.replace(/%27/g,"'");
15119     }
15120   };
15121
15122   /**
15123    * @name $browser#state
15124    *
15125    * @description
15126    * This method is a getter.
15127    *
15128    * Return history.state or null if history.state is undefined.
15129    *
15130    * @returns {object} state
15131    */
15132   self.state = function() {
15133     return cachedState;
15134   };
15135
15136   var urlChangeListeners = [],
15137       urlChangeInit = false;
15138
15139   function cacheStateAndFireUrlChange() {
15140     pendingLocation = null;
15141     cacheState();
15142     fireUrlChange();
15143   }
15144
15145   function getCurrentState() {
15146     try {
15147       return history.state;
15148     } catch (e) {
15149       // MSIE can reportedly throw when there is no state (UNCONFIRMED).
15150     }
15151   }
15152
15153   // This variable should be used *only* inside the cacheState function.
15154   var lastCachedState = null;
15155   function cacheState() {
15156     // This should be the only place in $browser where `history.state` is read.
15157     cachedState = getCurrentState();
15158     cachedState = isUndefined(cachedState) ? null : cachedState;
15159
15160     // Prevent callbacks fo fire twice if both hashchange & popstate were fired.
15161     if (equals(cachedState, lastCachedState)) {
15162       cachedState = lastCachedState;
15163     }
15164     lastCachedState = cachedState;
15165   }
15166
15167   function fireUrlChange() {
15168     if (lastBrowserUrl === self.url() && lastHistoryState === cachedState) {
15169       return;
15170     }
15171
15172     lastBrowserUrl = self.url();
15173     lastHistoryState = cachedState;
15174     forEach(urlChangeListeners, function(listener) {
15175       listener(self.url(), cachedState);
15176     });
15177   }
15178
15179   /**
15180    * @name $browser#onUrlChange
15181    *
15182    * @description
15183    * Register callback function that will be called, when url changes.
15184    *
15185    * It's only called when the url is changed from outside of angular:
15186    * - user types different url into address bar
15187    * - user clicks on history (forward/back) button
15188    * - user clicks on a link
15189    *
15190    * It's not called when url is changed by $browser.url() method
15191    *
15192    * The listener gets called with new url as parameter.
15193    *
15194    * NOTE: this api is intended for use only by the $location service. Please use the
15195    * {@link ng.$location $location service} to monitor url changes in angular apps.
15196    *
15197    * @param {function(string)} listener Listener function to be called when url changes.
15198    * @return {function(string)} Returns the registered listener fn - handy if the fn is anonymous.
15199    */
15200   self.onUrlChange = function(callback) {
15201     // TODO(vojta): refactor to use node's syntax for events
15202     if (!urlChangeInit) {
15203       // We listen on both (hashchange/popstate) when available, as some browsers (e.g. Opera)
15204       // don't fire popstate when user change the address bar and don't fire hashchange when url
15205       // changed by push/replaceState
15206
15207       // html5 history api - popstate event
15208       if ($sniffer.history) jqLite(window).on('popstate', cacheStateAndFireUrlChange);
15209       // hashchange event
15210       jqLite(window).on('hashchange', cacheStateAndFireUrlChange);
15211
15212       urlChangeInit = true;
15213     }
15214
15215     urlChangeListeners.push(callback);
15216     return callback;
15217   };
15218
15219   /**
15220    * @private
15221    * Remove popstate and hashchange handler from window.
15222    *
15223    * NOTE: this api is intended for use only by $rootScope.
15224    */
15225   self.$$applicationDestroyed = function() {
15226     jqLite(window).off('hashchange popstate', cacheStateAndFireUrlChange);
15227   };
15228
15229   /**
15230    * Checks whether the url has changed outside of Angular.
15231    * Needs to be exported to be able to check for changes that have been done in sync,
15232    * as hashchange/popstate events fire in async.
15233    */
15234   self.$$checkUrlChange = fireUrlChange;
15235
15236   //////////////////////////////////////////////////////////////
15237   // Misc API
15238   //////////////////////////////////////////////////////////////
15239
15240   /**
15241    * @name $browser#baseHref
15242    *
15243    * @description
15244    * Returns current <base href>
15245    * (always relative - without domain)
15246    *
15247    * @returns {string} The current base href
15248    */
15249   self.baseHref = function() {
15250     var href = baseElement.attr('href');
15251     return href ? href.replace(/^(https?\:)?\/\/[^\/]*/, '') : '';
15252   };
15253
15254   /**
15255    * @name $browser#defer
15256    * @param {function()} fn A function, who's execution should be deferred.
15257    * @param {number=} [delay=0] of milliseconds to defer the function execution.
15258    * @returns {*} DeferId that can be used to cancel the task via `$browser.defer.cancel()`.
15259    *
15260    * @description
15261    * Executes a fn asynchronously via `setTimeout(fn, delay)`.
15262    *
15263    * Unlike when calling `setTimeout` directly, in test this function is mocked and instead of using
15264    * `setTimeout` in tests, the fns are queued in an array, which can be programmatically flushed
15265    * via `$browser.defer.flush()`.
15266    *
15267    */
15268   self.defer = function(fn, delay) {
15269     var timeoutId;
15270     outstandingRequestCount++;
15271     timeoutId = setTimeout(function() {
15272       delete pendingDeferIds[timeoutId];
15273       completeOutstandingRequest(fn);
15274     }, delay || 0);
15275     pendingDeferIds[timeoutId] = true;
15276     return timeoutId;
15277   };
15278
15279
15280   /**
15281    * @name $browser#defer.cancel
15282    *
15283    * @description
15284    * Cancels a deferred task identified with `deferId`.
15285    *
15286    * @param {*} deferId Token returned by the `$browser.defer` function.
15287    * @returns {boolean} Returns `true` if the task hasn't executed yet and was successfully
15288    *                    canceled.
15289    */
15290   self.defer.cancel = function(deferId) {
15291     if (pendingDeferIds[deferId]) {
15292       delete pendingDeferIds[deferId];
15293       clearTimeout(deferId);
15294       completeOutstandingRequest(noop);
15295       return true;
15296     }
15297     return false;
15298   };
15299
15300 }
15301
15302 function $BrowserProvider() {
15303   this.$get = ['$window', '$log', '$sniffer', '$document',
15304       function($window, $log, $sniffer, $document) {
15305         return new Browser($window, $document, $log, $sniffer);
15306       }];
15307 }
15308
15309 /**
15310  * @ngdoc service
15311  * @name $cacheFactory
15312  *
15313  * @description
15314  * Factory that constructs {@link $cacheFactory.Cache Cache} objects and gives access to
15315  * them.
15316  *
15317  * ```js
15318  *
15319  *  var cache = $cacheFactory('cacheId');
15320  *  expect($cacheFactory.get('cacheId')).toBe(cache);
15321  *  expect($cacheFactory.get('noSuchCacheId')).not.toBeDefined();
15322  *
15323  *  cache.put("key", "value");
15324  *  cache.put("another key", "another value");
15325  *
15326  *  // We've specified no options on creation
15327  *  expect(cache.info()).toEqual({id: 'cacheId', size: 2});
15328  *
15329  * ```
15330  *
15331  *
15332  * @param {string} cacheId Name or id of the newly created cache.
15333  * @param {object=} options Options object that specifies the cache behavior. Properties:
15334  *
15335  *   - `{number=}` `capacity` — turns the cache into LRU cache.
15336  *
15337  * @returns {object} Newly created cache object with the following set of methods:
15338  *
15339  * - `{object}` `info()` — Returns id, size, and options of cache.
15340  * - `{{*}}` `put({string} key, {*} value)` — Puts a new key-value pair into the cache and returns
15341  *   it.
15342  * - `{{*}}` `get({string} key)` — Returns cached value for `key` or undefined for cache miss.
15343  * - `{void}` `remove({string} key)` — Removes a key-value pair from the cache.
15344  * - `{void}` `removeAll()` — Removes all cached values.
15345  * - `{void}` `destroy()` — Removes references to this cache from $cacheFactory.
15346  *
15347  * @example
15348    <example module="cacheExampleApp">
15349      <file name="index.html">
15350        <div ng-controller="CacheController">
15351          <input ng-model="newCacheKey" placeholder="Key">
15352          <input ng-model="newCacheValue" placeholder="Value">
15353          <button ng-click="put(newCacheKey, newCacheValue)">Cache</button>
15354
15355          <p ng-if="keys.length">Cached Values</p>
15356          <div ng-repeat="key in keys">
15357            <span ng-bind="key"></span>
15358            <span>: </span>
15359            <b ng-bind="cache.get(key)"></b>
15360          </div>
15361
15362          <p>Cache Info</p>
15363          <div ng-repeat="(key, value) in cache.info()">
15364            <span ng-bind="key"></span>
15365            <span>: </span>
15366            <b ng-bind="value"></b>
15367          </div>
15368        </div>
15369      </file>
15370      <file name="script.js">
15371        angular.module('cacheExampleApp', []).
15372          controller('CacheController', ['$scope', '$cacheFactory', function($scope, $cacheFactory) {
15373            $scope.keys = [];
15374            $scope.cache = $cacheFactory('cacheId');
15375            $scope.put = function(key, value) {
15376              if (angular.isUndefined($scope.cache.get(key))) {
15377                $scope.keys.push(key);
15378              }
15379              $scope.cache.put(key, angular.isUndefined(value) ? null : value);
15380            };
15381          }]);
15382      </file>
15383      <file name="style.css">
15384        p {
15385          margin: 10px 0 3px;
15386        }
15387      </file>
15388    </example>
15389  */
15390 function $CacheFactoryProvider() {
15391
15392   this.$get = function() {
15393     var caches = {};
15394
15395     function cacheFactory(cacheId, options) {
15396       if (cacheId in caches) {
15397         throw minErr('$cacheFactory')('iid', "CacheId '{0}' is already taken!", cacheId);
15398       }
15399
15400       var size = 0,
15401           stats = extend({}, options, {id: cacheId}),
15402           data = createMap(),
15403           capacity = (options && options.capacity) || Number.MAX_VALUE,
15404           lruHash = createMap(),
15405           freshEnd = null,
15406           staleEnd = null;
15407
15408       /**
15409        * @ngdoc type
15410        * @name $cacheFactory.Cache
15411        *
15412        * @description
15413        * A cache object used to store and retrieve data, primarily used by
15414        * {@link $http $http} and the {@link ng.directive:script script} directive to cache
15415        * templates and other data.
15416        *
15417        * ```js
15418        *  angular.module('superCache')
15419        *    .factory('superCache', ['$cacheFactory', function($cacheFactory) {
15420        *      return $cacheFactory('super-cache');
15421        *    }]);
15422        * ```
15423        *
15424        * Example test:
15425        *
15426        * ```js
15427        *  it('should behave like a cache', inject(function(superCache) {
15428        *    superCache.put('key', 'value');
15429        *    superCache.put('another key', 'another value');
15430        *
15431        *    expect(superCache.info()).toEqual({
15432        *      id: 'super-cache',
15433        *      size: 2
15434        *    });
15435        *
15436        *    superCache.remove('another key');
15437        *    expect(superCache.get('another key')).toBeUndefined();
15438        *
15439        *    superCache.removeAll();
15440        *    expect(superCache.info()).toEqual({
15441        *      id: 'super-cache',
15442        *      size: 0
15443        *    });
15444        *  }));
15445        * ```
15446        */
15447       return caches[cacheId] = {
15448
15449         /**
15450          * @ngdoc method
15451          * @name $cacheFactory.Cache#put
15452          * @kind function
15453          *
15454          * @description
15455          * Inserts a named entry into the {@link $cacheFactory.Cache Cache} object to be
15456          * retrieved later, and incrementing the size of the cache if the key was not already
15457          * present in the cache. If behaving like an LRU cache, it will also remove stale
15458          * entries from the set.
15459          *
15460          * It will not insert undefined values into the cache.
15461          *
15462          * @param {string} key the key under which the cached data is stored.
15463          * @param {*} value the value to store alongside the key. If it is undefined, the key
15464          *    will not be stored.
15465          * @returns {*} the value stored.
15466          */
15467         put: function(key, value) {
15468           if (isUndefined(value)) return;
15469           if (capacity < Number.MAX_VALUE) {
15470             var lruEntry = lruHash[key] || (lruHash[key] = {key: key});
15471
15472             refresh(lruEntry);
15473           }
15474
15475           if (!(key in data)) size++;
15476           data[key] = value;
15477
15478           if (size > capacity) {
15479             this.remove(staleEnd.key);
15480           }
15481
15482           return value;
15483         },
15484
15485         /**
15486          * @ngdoc method
15487          * @name $cacheFactory.Cache#get
15488          * @kind function
15489          *
15490          * @description
15491          * Retrieves named data stored in the {@link $cacheFactory.Cache Cache} object.
15492          *
15493          * @param {string} key the key of the data to be retrieved
15494          * @returns {*} the value stored.
15495          */
15496         get: function(key) {
15497           if (capacity < Number.MAX_VALUE) {
15498             var lruEntry = lruHash[key];
15499
15500             if (!lruEntry) return;
15501
15502             refresh(lruEntry);
15503           }
15504
15505           return data[key];
15506         },
15507
15508
15509         /**
15510          * @ngdoc method
15511          * @name $cacheFactory.Cache#remove
15512          * @kind function
15513          *
15514          * @description
15515          * Removes an entry from the {@link $cacheFactory.Cache Cache} object.
15516          *
15517          * @param {string} key the key of the entry to be removed
15518          */
15519         remove: function(key) {
15520           if (capacity < Number.MAX_VALUE) {
15521             var lruEntry = lruHash[key];
15522
15523             if (!lruEntry) return;
15524
15525             if (lruEntry == freshEnd) freshEnd = lruEntry.p;
15526             if (lruEntry == staleEnd) staleEnd = lruEntry.n;
15527             link(lruEntry.n,lruEntry.p);
15528
15529             delete lruHash[key];
15530           }
15531
15532           if (!(key in data)) return;
15533
15534           delete data[key];
15535           size--;
15536         },
15537
15538
15539         /**
15540          * @ngdoc method
15541          * @name $cacheFactory.Cache#removeAll
15542          * @kind function
15543          *
15544          * @description
15545          * Clears the cache object of any entries.
15546          */
15547         removeAll: function() {
15548           data = createMap();
15549           size = 0;
15550           lruHash = createMap();
15551           freshEnd = staleEnd = null;
15552         },
15553
15554
15555         /**
15556          * @ngdoc method
15557          * @name $cacheFactory.Cache#destroy
15558          * @kind function
15559          *
15560          * @description
15561          * Destroys the {@link $cacheFactory.Cache Cache} object entirely,
15562          * removing it from the {@link $cacheFactory $cacheFactory} set.
15563          */
15564         destroy: function() {
15565           data = null;
15566           stats = null;
15567           lruHash = null;
15568           delete caches[cacheId];
15569         },
15570
15571
15572         /**
15573          * @ngdoc method
15574          * @name $cacheFactory.Cache#info
15575          * @kind function
15576          *
15577          * @description
15578          * Retrieve information regarding a particular {@link $cacheFactory.Cache Cache}.
15579          *
15580          * @returns {object} an object with the following properties:
15581          *   <ul>
15582          *     <li>**id**: the id of the cache instance</li>
15583          *     <li>**size**: the number of entries kept in the cache instance</li>
15584          *     <li>**...**: any additional properties from the options object when creating the
15585          *       cache.</li>
15586          *   </ul>
15587          */
15588         info: function() {
15589           return extend({}, stats, {size: size});
15590         }
15591       };
15592
15593
15594       /**
15595        * makes the `entry` the freshEnd of the LRU linked list
15596        */
15597       function refresh(entry) {
15598         if (entry != freshEnd) {
15599           if (!staleEnd) {
15600             staleEnd = entry;
15601           } else if (staleEnd == entry) {
15602             staleEnd = entry.n;
15603           }
15604
15605           link(entry.n, entry.p);
15606           link(entry, freshEnd);
15607           freshEnd = entry;
15608           freshEnd.n = null;
15609         }
15610       }
15611
15612
15613       /**
15614        * bidirectionally links two entries of the LRU linked list
15615        */
15616       function link(nextEntry, prevEntry) {
15617         if (nextEntry != prevEntry) {
15618           if (nextEntry) nextEntry.p = prevEntry; //p stands for previous, 'prev' didn't minify
15619           if (prevEntry) prevEntry.n = nextEntry; //n stands for next, 'next' didn't minify
15620         }
15621       }
15622     }
15623
15624
15625   /**
15626    * @ngdoc method
15627    * @name $cacheFactory#info
15628    *
15629    * @description
15630    * Get information about all the caches that have been created
15631    *
15632    * @returns {Object} - key-value map of `cacheId` to the result of calling `cache#info`
15633    */
15634     cacheFactory.info = function() {
15635       var info = {};
15636       forEach(caches, function(cache, cacheId) {
15637         info[cacheId] = cache.info();
15638       });
15639       return info;
15640     };
15641
15642
15643   /**
15644    * @ngdoc method
15645    * @name $cacheFactory#get
15646    *
15647    * @description
15648    * Get access to a cache object by the `cacheId` used when it was created.
15649    *
15650    * @param {string} cacheId Name or id of a cache to access.
15651    * @returns {object} Cache object identified by the cacheId or undefined if no such cache.
15652    */
15653     cacheFactory.get = function(cacheId) {
15654       return caches[cacheId];
15655     };
15656
15657
15658     return cacheFactory;
15659   };
15660 }
15661
15662 /**
15663  * @ngdoc service
15664  * @name $templateCache
15665  *
15666  * @description
15667  * The first time a template is used, it is loaded in the template cache for quick retrieval. You
15668  * can load templates directly into the cache in a `script` tag, or by consuming the
15669  * `$templateCache` service directly.
15670  *
15671  * Adding via the `script` tag:
15672  *
15673  * ```html
15674  *   <script type="text/ng-template" id="templateId.html">
15675  *     <p>This is the content of the template</p>
15676  *   </script>
15677  * ```
15678  *
15679  * **Note:** the `script` tag containing the template does not need to be included in the `head` of
15680  * the document, but it must be a descendent of the {@link ng.$rootElement $rootElement} (IE,
15681  * element with ng-app attribute), otherwise the template will be ignored.
15682  *
15683  * Adding via the `$templateCache` service:
15684  *
15685  * ```js
15686  * var myApp = angular.module('myApp', []);
15687  * myApp.run(function($templateCache) {
15688  *   $templateCache.put('templateId.html', 'This is the content of the template');
15689  * });
15690  * ```
15691  *
15692  * To retrieve the template later, simply use it in your HTML:
15693  * ```html
15694  * <div ng-include=" 'templateId.html' "></div>
15695  * ```
15696  *
15697  * or get it via Javascript:
15698  * ```js
15699  * $templateCache.get('templateId.html')
15700  * ```
15701  *
15702  * See {@link ng.$cacheFactory $cacheFactory}.
15703  *
15704  */
15705 function $TemplateCacheProvider() {
15706   this.$get = ['$cacheFactory', function($cacheFactory) {
15707     return $cacheFactory('templates');
15708   }];
15709 }
15710
15711 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
15712  *     Any commits to this file should be reviewed with security in mind.  *
15713  *   Changes to this file can potentially create security vulnerabilities. *
15714  *          An approval from 2 Core members with history of modifying      *
15715  *                         this file is required.                          *
15716  *                                                                         *
15717  *  Does the change somehow allow for arbitrary javascript to be executed? *
15718  *    Or allows for someone to change the prototype of built-in objects?   *
15719  *     Or gives undesired access to variables likes document or window?    *
15720  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
15721
15722 /* ! VARIABLE/FUNCTION NAMING CONVENTIONS THAT APPLY TO THIS FILE!
15723  *
15724  * DOM-related variables:
15725  *
15726  * - "node" - DOM Node
15727  * - "element" - DOM Element or Node
15728  * - "$node" or "$element" - jqLite-wrapped node or element
15729  *
15730  *
15731  * Compiler related stuff:
15732  *
15733  * - "linkFn" - linking fn of a single directive
15734  * - "nodeLinkFn" - function that aggregates all linking fns for a particular node
15735  * - "childLinkFn" -  function that aggregates all linking fns for child nodes of a particular node
15736  * - "compositeLinkFn" - function that aggregates all linking fns for a compilation root (nodeList)
15737  */
15738
15739
15740 /**
15741  * @ngdoc service
15742  * @name $compile
15743  * @kind function
15744  *
15745  * @description
15746  * Compiles an HTML string or DOM into a template and produces a template function, which
15747  * can then be used to link {@link ng.$rootScope.Scope `scope`} and the template together.
15748  *
15749  * The compilation is a process of walking the DOM tree and matching DOM elements to
15750  * {@link ng.$compileProvider#directive directives}.
15751  *
15752  * <div class="alert alert-warning">
15753  * **Note:** This document is an in-depth reference of all directive options.
15754  * For a gentle introduction to directives with examples of common use cases,
15755  * see the {@link guide/directive directive guide}.
15756  * </div>
15757  *
15758  * ## Comprehensive Directive API
15759  *
15760  * There are many different options for a directive.
15761  *
15762  * The difference resides in the return value of the factory function.
15763  * You can either return a "Directive Definition Object" (see below) that defines the directive properties,
15764  * or just the `postLink` function (all other properties will have the default values).
15765  *
15766  * <div class="alert alert-success">
15767  * **Best Practice:** It's recommended to use the "directive definition object" form.
15768  * </div>
15769  *
15770  * Here's an example directive declared with a Directive Definition Object:
15771  *
15772  * ```js
15773  *   var myModule = angular.module(...);
15774  *
15775  *   myModule.directive('directiveName', function factory(injectables) {
15776  *     var directiveDefinitionObject = {
15777  *       priority: 0,
15778  *       template: '<div></div>', // or // function(tElement, tAttrs) { ... },
15779  *       // or
15780  *       // templateUrl: 'directive.html', // or // function(tElement, tAttrs) { ... },
15781  *       transclude: false,
15782  *       restrict: 'A',
15783  *       templateNamespace: 'html',
15784  *       scope: false,
15785  *       controller: function($scope, $element, $attrs, $transclude, otherInjectables) { ... },
15786  *       controllerAs: 'stringIdentifier',
15787  *       bindToController: false,
15788  *       require: 'siblingDirectiveName', // or // ['^parentDirectiveName', '?optionalDirectiveName', '?^optionalParent'],
15789  *       compile: function compile(tElement, tAttrs, transclude) {
15790  *         return {
15791  *           pre: function preLink(scope, iElement, iAttrs, controller) { ... },
15792  *           post: function postLink(scope, iElement, iAttrs, controller) { ... }
15793  *         }
15794  *         // or
15795  *         // return function postLink( ... ) { ... }
15796  *       },
15797  *       // or
15798  *       // link: {
15799  *       //  pre: function preLink(scope, iElement, iAttrs, controller) { ... },
15800  *       //  post: function postLink(scope, iElement, iAttrs, controller) { ... }
15801  *       // }
15802  *       // or
15803  *       // link: function postLink( ... ) { ... }
15804  *     };
15805  *     return directiveDefinitionObject;
15806  *   });
15807  * ```
15808  *
15809  * <div class="alert alert-warning">
15810  * **Note:** Any unspecified options will use the default value. You can see the default values below.
15811  * </div>
15812  *
15813  * Therefore the above can be simplified as:
15814  *
15815  * ```js
15816  *   var myModule = angular.module(...);
15817  *
15818  *   myModule.directive('directiveName', function factory(injectables) {
15819  *     var directiveDefinitionObject = {
15820  *       link: function postLink(scope, iElement, iAttrs) { ... }
15821  *     };
15822  *     return directiveDefinitionObject;
15823  *     // or
15824  *     // return function postLink(scope, iElement, iAttrs) { ... }
15825  *   });
15826  * ```
15827  *
15828  *
15829  *
15830  * ### Directive Definition Object
15831  *
15832  * The directive definition object provides instructions to the {@link ng.$compile
15833  * compiler}. The attributes are:
15834  *
15835  * #### `multiElement`
15836  * When this property is set to true, the HTML compiler will collect DOM nodes between
15837  * nodes with the attributes `directive-name-start` and `directive-name-end`, and group them
15838  * together as the directive elements. It is recommended that this feature be used on directives
15839  * which are not strictly behavioral (such as {@link ngClick}), and which
15840  * do not manipulate or replace child nodes (such as {@link ngInclude}).
15841  *
15842  * #### `priority`
15843  * When there are multiple directives defined on a single DOM element, sometimes it
15844  * is necessary to specify the order in which the directives are applied. The `priority` is used
15845  * to sort the directives before their `compile` functions get called. Priority is defined as a
15846  * number. Directives with greater numerical `priority` are compiled first. Pre-link functions
15847  * are also run in priority order, but post-link functions are run in reverse order. The order
15848  * of directives with the same priority is undefined. The default priority is `0`.
15849  *
15850  * #### `terminal`
15851  * If set to true then the current `priority` will be the last set of directives
15852  * which will execute (any directives at the current priority will still execute
15853  * as the order of execution on same `priority` is undefined). Note that expressions
15854  * and other directives used in the directive's template will also be excluded from execution.
15855  *
15856  * #### `scope`
15857  * The scope property can be `true`, an object or a falsy value:
15858  *
15859  * * **falsy:** No scope will be created for the directive. The directive will use its parent's scope.
15860  *
15861  * * **`true`:** A new child scope that prototypically inherits from its parent will be created for
15862  * the directive's element. If multiple directives on the same element request a new scope,
15863  * only one new scope is created. The new scope rule does not apply for the root of the template
15864  * since the root of the template always gets a new scope.
15865  *
15866  * * **`{...}` (an object hash):** A new "isolate" scope is created for the directive's element. The
15867  * 'isolate' scope differs from normal scope in that it does not prototypically inherit from its parent
15868  * scope. This is useful when creating reusable components, which should not accidentally read or modify
15869  * data in the parent scope.
15870  *
15871  * The 'isolate' scope object hash defines a set of local scope properties derived from attributes on the
15872  * directive's element. These local properties are useful for aliasing values for templates. The keys in
15873  * the object hash map to the name of the property on the isolate scope; the values define how the property
15874  * is bound to the parent scope, via matching attributes on the directive's element:
15875  *
15876  * * `@` or `@attr` - bind a local scope property to the value of DOM attribute. The result is
15877  *   always a string since DOM attributes are strings. If no `attr` name is specified then the
15878  *   attribute name is assumed to be the same as the local name. Given `<my-component
15879  *   my-attr="hello {{name}}">` and the isolate scope definition `scope: { localName:'@myAttr' }`,
15880  *   the directive's scope property `localName` will reflect the interpolated value of `hello
15881  *   {{name}}`. As the `name` attribute changes so will the `localName` property on the directive's
15882  *   scope. The `name` is read from the parent scope (not the directive's scope).
15883  *
15884  * * `=` or `=attr` - set up a bidirectional binding between a local scope property and an expression
15885  *   passed via the attribute `attr`. The expression is evaluated in the context of the parent scope.
15886  *   If no `attr` name is specified then the attribute name is assumed to be the same as the local
15887  *   name. Given `<my-component my-attr="parentModel">` and the isolate scope definition `scope: {
15888  *   localModel: '=myAttr' }`, the property `localModel` on the directive's scope will reflect the
15889  *   value of `parentModel` on the parent scope. Changes to `parentModel` will be reflected in
15890  *   `localModel` and vice versa. Optional attributes should be marked as such with a question mark:
15891  *   `=?` or `=?attr`. If the binding expression is non-assignable, or if the attribute isn't
15892  *   optional and doesn't exist, an exception ({@link error/$compile/nonassign `$compile:nonassign`})
15893  *   will be thrown upon discovering changes to the local value, since it will be impossible to sync
15894  *   them back to the parent scope. By default, the {@link ng.$rootScope.Scope#$watch `$watch`}
15895  *   method is used for tracking changes, and the equality check is based on object identity.
15896  *   However, if an object literal or an array literal is passed as the binding expression, the
15897  *   equality check is done by value (using the {@link angular.equals} function). It's also possible
15898  *   to watch the evaluated value shallowly with {@link ng.$rootScope.Scope#$watchCollection
15899  *   `$watchCollection`}: use `=*` or `=*attr` (`=*?` or `=*?attr` if the attribute is optional).
15900  *
15901   * * `<` or `<attr` - set up a one-way (one-directional) binding between a local scope property and an
15902  *   expression passed via the attribute `attr`. The expression is evaluated in the context of the
15903  *   parent scope. If no `attr` name is specified then the attribute name is assumed to be the same as the
15904  *   local name. You can also make the binding optional by adding `?`: `<?` or `<?attr`.
15905  *
15906  *   For example, given `<my-component my-attr="parentModel">` and directive definition of
15907  *   `scope: { localModel:'<myAttr' }`, then the isolated scope property `localModel` will reflect the
15908  *   value of `parentModel` on the parent scope. Any changes to `parentModel` will be reflected
15909  *   in `localModel`, but changes in `localModel` will not reflect in `parentModel`. There are however
15910  *   two caveats:
15911  *     1. one-way binding does not copy the value from the parent to the isolate scope, it simply
15912  *     sets the same value. That means if your bound value is an object, changes to its properties
15913  *     in the isolated scope will be reflected in the parent scope (because both reference the same object).
15914  *     2. one-way binding watches changes to the **identity** of the parent value. That means the
15915  *     {@link ng.$rootScope.Scope#$watch `$watch`} on the parent value only fires if the reference
15916  *     to the value has changed. In most cases, this should not be of concern, but can be important
15917  *     to know if you one-way bind to an object, and then replace that object in the isolated scope.
15918  *     If you now change a property of the object in your parent scope, the change will not be
15919  *     propagated to the isolated scope, because the identity of the object on the parent scope
15920  *     has not changed. Instead you must assign a new object.
15921  *
15922  *   One-way binding is useful if you do not plan to propagate changes to your isolated scope bindings
15923  *   back to the parent. However, it does not make this completely impossible.
15924  *
15925  * * `&` or `&attr` - provides a way to execute an expression in the context of the parent scope. If
15926  *   no `attr` name is specified then the attribute name is assumed to be the same as the local name.
15927  *   Given `<my-component my-attr="count = count + value">` and the isolate scope definition `scope: {
15928  *   localFn:'&myAttr' }`, the isolate scope property `localFn` will point to a function wrapper for
15929  *   the `count = count + value` expression. Often it's desirable to pass data from the isolated scope
15930  *   via an expression to the parent scope. This can be done by passing a map of local variable names
15931  *   and values into the expression wrapper fn. For example, if the expression is `increment(amount)`
15932  *   then we can specify the amount value by calling the `localFn` as `localFn({amount: 22})`.
15933  *
15934  * In general it's possible to apply more than one directive to one element, but there might be limitations
15935  * depending on the type of scope required by the directives. The following points will help explain these limitations.
15936  * For simplicity only two directives are taken into account, but it is also applicable for several directives:
15937  *
15938  * * **no scope** + **no scope** => Two directives which don't require their own scope will use their parent's scope
15939  * * **child scope** + **no scope** =>  Both directives will share one single child scope
15940  * * **child scope** + **child scope** =>  Both directives will share one single child scope
15941  * * **isolated scope** + **no scope** =>  The isolated directive will use it's own created isolated scope. The other directive will use
15942  * its parent's scope
15943  * * **isolated scope** + **child scope** =>  **Won't work!** Only one scope can be related to one element. Therefore these directives cannot
15944  * be applied to the same element.
15945  * * **isolated scope** + **isolated scope**  =>  **Won't work!** Only one scope can be related to one element. Therefore these directives
15946  * cannot be applied to the same element.
15947  *
15948  *
15949  * #### `bindToController`
15950  * This property is used to bind scope properties directly to the controller. It can be either
15951  * `true` or an object hash with the same format as the `scope` property. Additionally, a controller
15952  * alias must be set, either by using `controllerAs: 'myAlias'` or by specifying the alias in the controller
15953  * definition: `controller: 'myCtrl as myAlias'`.
15954  *
15955  * When an isolate scope is used for a directive (see above), `bindToController: true` will
15956  * allow a component to have its properties bound to the controller, rather than to scope.
15957  *
15958  * After the controller is instantiated, the initial values of the isolate scope bindings will be bound to the controller
15959  * properties. You can access these bindings once they have been initialized by providing a controller method called
15960  * `$onInit`, which is called after all the controllers on an element have been constructed and had their bindings
15961  * initialized.
15962  *
15963  * <div class="alert alert-warning">
15964  * **Deprecation warning:** although bindings for non-ES6 class controllers are currently
15965  * bound to `this` before the controller constructor is called, this use is now deprecated. Please place initialization
15966  * code that relies upon bindings inside a `$onInit` method on the controller, instead.
15967  * </div>
15968  *
15969  * It is also possible to set `bindToController` to an object hash with the same format as the `scope` property.
15970  * This will set up the scope bindings to the controller directly. Note that `scope` can still be used
15971  * to define which kind of scope is created. By default, no scope is created. Use `scope: {}` to create an isolate
15972  * scope (useful for component directives).
15973  *
15974  * If both `bindToController` and `scope` are defined and have object hashes, `bindToController` overrides `scope`.
15975  *
15976  *
15977  * #### `controller`
15978  * Controller constructor function. The controller is instantiated before the
15979  * pre-linking phase and can be accessed by other directives (see
15980  * `require` attribute). This allows the directives to communicate with each other and augment
15981  * each other's behavior. The controller is injectable (and supports bracket notation) with the following locals:
15982  *
15983  * * `$scope` - Current scope associated with the element
15984  * * `$element` - Current element
15985  * * `$attrs` - Current attributes object for the element
15986  * * `$transclude` - A transclude linking function pre-bound to the correct transclusion scope:
15987  *   `function([scope], cloneLinkingFn, futureParentElement, slotName)`:
15988  *    * `scope`: (optional) override the scope.
15989  *    * `cloneLinkingFn`: (optional) argument to create clones of the original transcluded content.
15990  *    * `futureParentElement` (optional):
15991  *        * defines the parent to which the `cloneLinkingFn` will add the cloned elements.
15992  *        * default: `$element.parent()` resp. `$element` for `transclude:'element'` resp. `transclude:true`.
15993  *        * only needed for transcludes that are allowed to contain non html elements (e.g. SVG elements)
15994  *          and when the `cloneLinkinFn` is passed,
15995  *          as those elements need to created and cloned in a special way when they are defined outside their
15996  *          usual containers (e.g. like `<svg>`).
15997  *        * See also the `directive.templateNamespace` property.
15998  *    * `slotName`: (optional) the name of the slot to transclude. If falsy (e.g. `null`, `undefined` or `''`)
15999  *      then the default translusion is provided.
16000  *    The `$transclude` function also has a method on it, `$transclude.isSlotFilled(slotName)`, which returns
16001  *    `true` if the specified slot contains content (i.e. one or more DOM nodes).
16002  *
16003  * The controller can provide the following methods that act as life-cycle hooks:
16004  * * `$onInit` - Called on each controller after all the controllers on an element have been constructed and
16005  *   had their bindings initialized (and before the pre &amp; post linking functions for the directives on
16006  *   this element). This is a good place to put initialization code for your controller.
16007  *
16008  * #### `require`
16009  * Require another directive and inject its controller as the fourth argument to the linking function. The
16010  * `require` property can be a string, an array or an object:
16011  * * a **string** containing the name of the directive to pass to the linking function
16012  * * an **array** containing the names of directives to pass to the linking function. The argument passed to the
16013  * linking function will be an array of controllers in the same order as the names in the `require` property
16014  * * an **object** whose property values are the names of the directives to pass to the linking function. The argument
16015  * passed to the linking function will also be an object with matching keys, whose values will hold the corresponding
16016  * controllers.
16017  *
16018  * If the `require` property is an object and `bindToController` is truthy, then the required controllers are
16019  * bound to the controller using the keys of the `require` property. This binding occurs after all the controllers
16020  * have been constructed but before `$onInit` is called.
16021  * See the {@link $compileProvider#component} helper for an example of how this can be used.
16022  *
16023  * If no such required directive(s) can be found, or if the directive does not have a controller, then an error is
16024  * raised (unless no link function is specified and the required controllers are not being bound to the directive
16025  * controller, in which case error checking is skipped). The name can be prefixed with:
16026  *
16027  * * (no prefix) - Locate the required controller on the current element. Throw an error if not found.
16028  * * `?` - Attempt to locate the required controller or pass `null` to the `link` fn if not found.
16029  * * `^` - Locate the required controller by searching the element and its parents. Throw an error if not found.
16030  * * `^^` - Locate the required controller by searching the element's parents. Throw an error if not found.
16031  * * `?^` - Attempt to locate the required controller by searching the element and its parents or pass
16032  *   `null` to the `link` fn if not found.
16033  * * `?^^` - Attempt to locate the required controller by searching the element's parents, or pass
16034  *   `null` to the `link` fn if not found.
16035  *
16036  *
16037  * #### `controllerAs`
16038  * Identifier name for a reference to the controller in the directive's scope.
16039  * This allows the controller to be referenced from the directive template. This is especially
16040  * useful when a directive is used as component, i.e. with an `isolate` scope. It's also possible
16041  * to use it in a directive without an `isolate` / `new` scope, but you need to be aware that the
16042  * `controllerAs` reference might overwrite a property that already exists on the parent scope.
16043  *
16044  *
16045  * #### `restrict`
16046  * String of subset of `EACM` which restricts the directive to a specific directive
16047  * declaration style. If omitted, the defaults (elements and attributes) are used.
16048  *
16049  * * `E` - Element name (default): `<my-directive></my-directive>`
16050  * * `A` - Attribute (default): `<div my-directive="exp"></div>`
16051  * * `C` - Class: `<div class="my-directive: exp;"></div>`
16052  * * `M` - Comment: `<!-- directive: my-directive exp -->`
16053  *
16054  *
16055  * #### `templateNamespace`
16056  * String representing the document type used by the markup in the template.
16057  * AngularJS needs this information as those elements need to be created and cloned
16058  * in a special way when they are defined outside their usual containers like `<svg>` and `<math>`.
16059  *
16060  * * `html` - All root nodes in the template are HTML. Root nodes may also be
16061  *   top-level elements such as `<svg>` or `<math>`.
16062  * * `svg` - The root nodes in the template are SVG elements (excluding `<math>`).
16063  * * `math` - The root nodes in the template are MathML elements (excluding `<svg>`).
16064  *
16065  * If no `templateNamespace` is specified, then the namespace is considered to be `html`.
16066  *
16067  * #### `template`
16068  * HTML markup that may:
16069  * * Replace the contents of the directive's element (default).
16070  * * Replace the directive's element itself (if `replace` is true - DEPRECATED).
16071  * * Wrap the contents of the directive's element (if `transclude` is true).
16072  *
16073  * Value may be:
16074  *
16075  * * A string. For example `<div red-on-hover>{{delete_str}}</div>`.
16076  * * A function which takes two arguments `tElement` and `tAttrs` (described in the `compile`
16077  *   function api below) and returns a string value.
16078  *
16079  *
16080  * #### `templateUrl`
16081  * This is similar to `template` but the template is loaded from the specified URL, asynchronously.
16082  *
16083  * Because template loading is asynchronous the compiler will suspend compilation of directives on that element
16084  * for later when the template has been resolved.  In the meantime it will continue to compile and link
16085  * sibling and parent elements as though this element had not contained any directives.
16086  *
16087  * The compiler does not suspend the entire compilation to wait for templates to be loaded because this
16088  * would result in the whole app "stalling" until all templates are loaded asynchronously - even in the
16089  * case when only one deeply nested directive has `templateUrl`.
16090  *
16091  * Template loading is asynchronous even if the template has been preloaded into the {@link $templateCache}
16092  *
16093  * You can specify `templateUrl` as a string representing the URL or as a function which takes two
16094  * arguments `tElement` and `tAttrs` (described in the `compile` function api below) and returns
16095  * a string value representing the url.  In either case, the template URL is passed through {@link
16096  * $sce#getTrustedResourceUrl $sce.getTrustedResourceUrl}.
16097  *
16098  *
16099  * #### `replace` ([*DEPRECATED*!], will be removed in next major release - i.e. v2.0)
16100  * specify what the template should replace. Defaults to `false`.
16101  *
16102  * * `true` - the template will replace the directive's element.
16103  * * `false` - the template will replace the contents of the directive's element.
16104  *
16105  * The replacement process migrates all of the attributes / classes from the old element to the new
16106  * one. See the {@link guide/directive#template-expanding-directive
16107  * Directives Guide} for an example.
16108  *
16109  * There are very few scenarios where element replacement is required for the application function,
16110  * the main one being reusable custom components that are used within SVG contexts
16111  * (because SVG doesn't work with custom elements in the DOM tree).
16112  *
16113  * #### `transclude`
16114  * Extract the contents of the element where the directive appears and make it available to the directive.
16115  * The contents are compiled and provided to the directive as a **transclusion function**. See the
16116  * {@link $compile#transclusion Transclusion} section below.
16117  *
16118  *
16119  * #### `compile`
16120  *
16121  * ```js
16122  *   function compile(tElement, tAttrs, transclude) { ... }
16123  * ```
16124  *
16125  * The compile function deals with transforming the template DOM. Since most directives do not do
16126  * template transformation, it is not used often. The compile function takes the following arguments:
16127  *
16128  *   * `tElement` - template element - The element where the directive has been declared. It is
16129  *     safe to do template transformation on the element and child elements only.
16130  *
16131  *   * `tAttrs` - template attributes - Normalized list of attributes declared on this element shared
16132  *     between all directive compile functions.
16133  *
16134  *   * `transclude` -  [*DEPRECATED*!] A transclude linking function: `function(scope, cloneLinkingFn)`
16135  *
16136  * <div class="alert alert-warning">
16137  * **Note:** The template instance and the link instance may be different objects if the template has
16138  * been cloned. For this reason it is **not** safe to do anything other than DOM transformations that
16139  * apply to all cloned DOM nodes within the compile function. Specifically, DOM listener registration
16140  * should be done in a linking function rather than in a compile function.
16141  * </div>
16142
16143  * <div class="alert alert-warning">
16144  * **Note:** The compile function cannot handle directives that recursively use themselves in their
16145  * own templates or compile functions. Compiling these directives results in an infinite loop and
16146  * stack overflow errors.
16147  *
16148  * This can be avoided by manually using $compile in the postLink function to imperatively compile
16149  * a directive's template instead of relying on automatic template compilation via `template` or
16150  * `templateUrl` declaration or manual compilation inside the compile function.
16151  * </div>
16152  *
16153  * <div class="alert alert-danger">
16154  * **Note:** The `transclude` function that is passed to the compile function is deprecated, as it
16155  *   e.g. does not know about the right outer scope. Please use the transclude function that is passed
16156  *   to the link function instead.
16157  * </div>
16158
16159  * A compile function can have a return value which can be either a function or an object.
16160  *
16161  * * returning a (post-link) function - is equivalent to registering the linking function via the
16162  *   `link` property of the config object when the compile function is empty.
16163  *
16164  * * returning an object with function(s) registered via `pre` and `post` properties - allows you to
16165  *   control when a linking function should be called during the linking phase. See info about
16166  *   pre-linking and post-linking functions below.
16167  *
16168  *
16169  * #### `link`
16170  * This property is used only if the `compile` property is not defined.
16171  *
16172  * ```js
16173  *   function link(scope, iElement, iAttrs, controller, transcludeFn) { ... }
16174  * ```
16175  *
16176  * The link function is responsible for registering DOM listeners as well as updating the DOM. It is
16177  * executed after the template has been cloned. This is where most of the directive logic will be
16178  * put.
16179  *
16180  *   * `scope` - {@link ng.$rootScope.Scope Scope} - The scope to be used by the
16181  *     directive for registering {@link ng.$rootScope.Scope#$watch watches}.
16182  *
16183  *   * `iElement` - instance element - The element where the directive is to be used. It is safe to
16184  *     manipulate the children of the element only in `postLink` function since the children have
16185  *     already been linked.
16186  *
16187  *   * `iAttrs` - instance attributes - Normalized list of attributes declared on this element shared
16188  *     between all directive linking functions.
16189  *
16190  *   * `controller` - the directive's required controller instance(s) - Instances are shared
16191  *     among all directives, which allows the directives to use the controllers as a communication
16192  *     channel. The exact value depends on the directive's `require` property:
16193  *       * no controller(s) required: the directive's own controller, or `undefined` if it doesn't have one
16194  *       * `string`: the controller instance
16195  *       * `array`: array of controller instances
16196  *
16197  *     If a required controller cannot be found, and it is optional, the instance is `null`,
16198  *     otherwise the {@link error:$compile:ctreq Missing Required Controller} error is thrown.
16199  *
16200  *     Note that you can also require the directive's own controller - it will be made available like
16201  *     any other controller.
16202  *
16203  *   * `transcludeFn` - A transclude linking function pre-bound to the correct transclusion scope.
16204  *     This is the same as the `$transclude`
16205  *     parameter of directive controllers, see there for details.
16206  *     `function([scope], cloneLinkingFn, futureParentElement)`.
16207  *
16208  * #### Pre-linking function
16209  *
16210  * Executed before the child elements are linked. Not safe to do DOM transformation since the
16211  * compiler linking function will fail to locate the correct elements for linking.
16212  *
16213  * #### Post-linking function
16214  *
16215  * Executed after the child elements are linked.
16216  *
16217  * Note that child elements that contain `templateUrl` directives will not have been compiled
16218  * and linked since they are waiting for their template to load asynchronously and their own
16219  * compilation and linking has been suspended until that occurs.
16220  *
16221  * It is safe to do DOM transformation in the post-linking function on elements that are not waiting
16222  * for their async templates to be resolved.
16223  *
16224  *
16225  * ### Transclusion
16226  *
16227  * Transclusion is the process of extracting a collection of DOM elements from one part of the DOM and
16228  * copying them to another part of the DOM, while maintaining their connection to the original AngularJS
16229  * scope from where they were taken.
16230  *
16231  * Transclusion is used (often with {@link ngTransclude}) to insert the
16232  * original contents of a directive's element into a specified place in the template of the directive.
16233  * The benefit of transclusion, over simply moving the DOM elements manually, is that the transcluded
16234  * content has access to the properties on the scope from which it was taken, even if the directive
16235  * has isolated scope.
16236  * See the {@link guide/directive#creating-a-directive-that-wraps-other-elements Directives Guide}.
16237  *
16238  * This makes it possible for the widget to have private state for its template, while the transcluded
16239  * content has access to its originating scope.
16240  *
16241  * <div class="alert alert-warning">
16242  * **Note:** When testing an element transclude directive you must not place the directive at the root of the
16243  * DOM fragment that is being compiled. See {@link guide/unit-testing#testing-transclusion-directives
16244  * Testing Transclusion Directives}.
16245  * </div>
16246  *
16247  * There are three kinds of transclusion depending upon whether you want to transclude just the contents of the
16248  * directive's element, the entire element or multiple parts of the element contents:
16249  *
16250  * * `true` - transclude the content (i.e. the child nodes) of the directive's element.
16251  * * `'element'` - transclude the whole of the directive's element including any directives on this
16252  *   element that defined at a lower priority than this directive. When used, the `template`
16253  *   property is ignored.
16254  * * **`{...}` (an object hash):** - map elements of the content onto transclusion "slots" in the template.
16255  *
16256  * **Mult-slot transclusion** is declared by providing an object for the `transclude` property.
16257  *
16258  * This object is a map where the keys are the name of the slot to fill and the value is an element selector
16259  * used to match the HTML to the slot. The element selector should be in normalized form (e.g. `myElement`)
16260  * and will match the standard element variants (e.g. `my-element`, `my:element`, `data-my-element`, etc).
16261  *
16262  * For further information check out the guide on {@link guide/directive#matching-directives Matching Directives}
16263  *
16264  * If the element selector is prefixed with a `?` then that slot is optional.
16265  *
16266  * For example, the transclude object `{ slotA: '?myCustomElement' }` maps `<my-custom-element>` elements to
16267  * the `slotA` slot, which can be accessed via the `$transclude` function or via the {@link ngTransclude} directive.
16268  *
16269  * Slots that are not marked as optional (`?`) will trigger a compile time error if there are no matching elements
16270  * in the transclude content. If you wish to know if an optional slot was filled with content, then you can call
16271  * `$transclude.isSlotFilled(slotName)` on the transclude function passed to the directive's link function and
16272  * injectable into the directive's controller.
16273  *
16274  *
16275  * #### Transclusion Functions
16276  *
16277  * When a directive requests transclusion, the compiler extracts its contents and provides a **transclusion
16278  * function** to the directive's `link` function and `controller`. This transclusion function is a special
16279  * **linking function** that will return the compiled contents linked to a new transclusion scope.
16280  *
16281  * <div class="alert alert-info">
16282  * If you are just using {@link ngTransclude} then you don't need to worry about this function, since
16283  * ngTransclude will deal with it for us.
16284  * </div>
16285  *
16286  * If you want to manually control the insertion and removal of the transcluded content in your directive
16287  * then you must use this transclude function. When you call a transclude function it returns a a jqLite/JQuery
16288  * object that contains the compiled DOM, which is linked to the correct transclusion scope.
16289  *
16290  * When you call a transclusion function you can pass in a **clone attach function**. This function accepts
16291  * two parameters, `function(clone, scope) { ... }`, where the `clone` is a fresh compiled copy of your transcluded
16292  * content and the `scope` is the newly created transclusion scope, to which the clone is bound.
16293  *
16294  * <div class="alert alert-info">
16295  * **Best Practice**: Always provide a `cloneFn` (clone attach function) when you call a transclude function
16296  * since you then get a fresh clone of the original DOM and also have access to the new transclusion scope.
16297  * </div>
16298  *
16299  * It is normal practice to attach your transcluded content (`clone`) to the DOM inside your **clone
16300  * attach function**:
16301  *
16302  * ```js
16303  * var transcludedContent, transclusionScope;
16304  *
16305  * $transclude(function(clone, scope) {
16306  *   element.append(clone);
16307  *   transcludedContent = clone;
16308  *   transclusionScope = scope;
16309  * });
16310  * ```
16311  *
16312  * Later, if you want to remove the transcluded content from your DOM then you should also destroy the
16313  * associated transclusion scope:
16314  *
16315  * ```js
16316  * transcludedContent.remove();
16317  * transclusionScope.$destroy();
16318  * ```
16319  *
16320  * <div class="alert alert-info">
16321  * **Best Practice**: if you intend to add and remove transcluded content manually in your directive
16322  * (by calling the transclude function to get the DOM and calling `element.remove()` to remove it),
16323  * then you are also responsible for calling `$destroy` on the transclusion scope.
16324  * </div>
16325  *
16326  * The built-in DOM manipulation directives, such as {@link ngIf}, {@link ngSwitch} and {@link ngRepeat}
16327  * automatically destroy their transcluded clones as necessary so you do not need to worry about this if
16328  * you are simply using {@link ngTransclude} to inject the transclusion into your directive.
16329  *
16330  *
16331  * #### Transclusion Scopes
16332  *
16333  * When you call a transclude function it returns a DOM fragment that is pre-bound to a **transclusion
16334  * scope**. This scope is special, in that it is a child of the directive's scope (and so gets destroyed
16335  * when the directive's scope gets destroyed) but it inherits the properties of the scope from which it
16336  * was taken.
16337  *
16338  * For example consider a directive that uses transclusion and isolated scope. The DOM hierarchy might look
16339  * like this:
16340  *
16341  * ```html
16342  * <div ng-app>
16343  *   <div isolate>
16344  *     <div transclusion>
16345  *     </div>
16346  *   </div>
16347  * </div>
16348  * ```
16349  *
16350  * The `$parent` scope hierarchy will look like this:
16351  *
16352    ```
16353    - $rootScope
16354      - isolate
16355        - transclusion
16356    ```
16357  *
16358  * but the scopes will inherit prototypically from different scopes to their `$parent`.
16359  *
16360    ```
16361    - $rootScope
16362      - transclusion
16363    - isolate
16364    ```
16365  *
16366  *
16367  * ### Attributes
16368  *
16369  * The {@link ng.$compile.directive.Attributes Attributes} object - passed as a parameter in the
16370  * `link()` or `compile()` functions. It has a variety of uses.
16371  *
16372  * * *Accessing normalized attribute names:* Directives like 'ngBind' can be expressed in many ways:
16373  *   'ng:bind', `data-ng-bind`, or 'x-ng-bind'. The attributes object allows for normalized access
16374  *   to the attributes.
16375  *
16376  * * *Directive inter-communication:* All directives share the same instance of the attributes
16377  *   object which allows the directives to use the attributes object as inter directive
16378  *   communication.
16379  *
16380  * * *Supports interpolation:* Interpolation attributes are assigned to the attribute object
16381  *   allowing other directives to read the interpolated value.
16382  *
16383  * * *Observing interpolated attributes:* Use `$observe` to observe the value changes of attributes
16384  *   that contain interpolation (e.g. `src="{{bar}}"`). Not only is this very efficient but it's also
16385  *   the only way to easily get the actual value because during the linking phase the interpolation
16386  *   hasn't been evaluated yet and so the value is at this time set to `undefined`.
16387  *
16388  * ```js
16389  * function linkingFn(scope, elm, attrs, ctrl) {
16390  *   // get the attribute value
16391  *   console.log(attrs.ngModel);
16392  *
16393  *   // change the attribute
16394  *   attrs.$set('ngModel', 'new value');
16395  *
16396  *   // observe changes to interpolated attribute
16397  *   attrs.$observe('ngModel', function(value) {
16398  *     console.log('ngModel has changed value to ' + value);
16399  *   });
16400  * }
16401  * ```
16402  *
16403  * ## Example
16404  *
16405  * <div class="alert alert-warning">
16406  * **Note**: Typically directives are registered with `module.directive`. The example below is
16407  * to illustrate how `$compile` works.
16408  * </div>
16409  *
16410  <example module="compileExample">
16411    <file name="index.html">
16412     <script>
16413       angular.module('compileExample', [], function($compileProvider) {
16414         // configure new 'compile' directive by passing a directive
16415         // factory function. The factory function injects the '$compile'
16416         $compileProvider.directive('compile', function($compile) {
16417           // directive factory creates a link function
16418           return function(scope, element, attrs) {
16419             scope.$watch(
16420               function(scope) {
16421                  // watch the 'compile' expression for changes
16422                 return scope.$eval(attrs.compile);
16423               },
16424               function(value) {
16425                 // when the 'compile' expression changes
16426                 // assign it into the current DOM
16427                 element.html(value);
16428
16429                 // compile the new DOM and link it to the current
16430                 // scope.
16431                 // NOTE: we only compile .childNodes so that
16432                 // we don't get into infinite loop compiling ourselves
16433                 $compile(element.contents())(scope);
16434               }
16435             );
16436           };
16437         });
16438       })
16439       .controller('GreeterController', ['$scope', function($scope) {
16440         $scope.name = 'Angular';
16441         $scope.html = 'Hello {{name}}';
16442       }]);
16443     </script>
16444     <div ng-controller="GreeterController">
16445       <input ng-model="name"> <br/>
16446       <textarea ng-model="html"></textarea> <br/>
16447       <div compile="html"></div>
16448     </div>
16449    </file>
16450    <file name="protractor.js" type="protractor">
16451      it('should auto compile', function() {
16452        var textarea = $('textarea');
16453        var output = $('div[compile]');
16454        // The initial state reads 'Hello Angular'.
16455        expect(output.getText()).toBe('Hello Angular');
16456        textarea.clear();
16457        textarea.sendKeys('{{name}}!');
16458        expect(output.getText()).toBe('Angular!');
16459      });
16460    </file>
16461  </example>
16462
16463  *
16464  *
16465  * @param {string|DOMElement} element Element or HTML string to compile into a template function.
16466  * @param {function(angular.Scope, cloneAttachFn=)} transclude function available to directives - DEPRECATED.
16467  *
16468  * <div class="alert alert-danger">
16469  * **Note:** Passing a `transclude` function to the $compile function is deprecated, as it
16470  *   e.g. will not use the right outer scope. Please pass the transclude function as a
16471  *   `parentBoundTranscludeFn` to the link function instead.
16472  * </div>
16473  *
16474  * @param {number} maxPriority only apply directives lower than given priority (Only effects the
16475  *                 root element(s), not their children)
16476  * @returns {function(scope, cloneAttachFn=, options=)} a link function which is used to bind template
16477  * (a DOM element/tree) to a scope. Where:
16478  *
16479  *  * `scope` - A {@link ng.$rootScope.Scope Scope} to bind to.
16480  *  * `cloneAttachFn` - If `cloneAttachFn` is provided, then the link function will clone the
16481  *  `template` and call the `cloneAttachFn` function allowing the caller to attach the
16482  *  cloned elements to the DOM document at the appropriate place. The `cloneAttachFn` is
16483  *  called as: <br/> `cloneAttachFn(clonedElement, scope)` where:
16484  *
16485  *      * `clonedElement` - is a clone of the original `element` passed into the compiler.
16486  *      * `scope` - is the current scope with which the linking function is working with.
16487  *
16488  *  * `options` - An optional object hash with linking options. If `options` is provided, then the following
16489  *  keys may be used to control linking behavior:
16490  *
16491  *      * `parentBoundTranscludeFn` - the transclude function made available to
16492  *        directives; if given, it will be passed through to the link functions of
16493  *        directives found in `element` during compilation.
16494  *      * `transcludeControllers` - an object hash with keys that map controller names
16495  *        to a hash with the key `instance`, which maps to the controller instance;
16496  *        if given, it will make the controllers available to directives on the compileNode:
16497  *        ```
16498  *        {
16499  *          parent: {
16500  *            instance: parentControllerInstance
16501  *          }
16502  *        }
16503  *        ```
16504  *      * `futureParentElement` - defines the parent to which the `cloneAttachFn` will add
16505  *        the cloned elements; only needed for transcludes that are allowed to contain non html
16506  *        elements (e.g. SVG elements). See also the directive.controller property.
16507  *
16508  * Calling the linking function returns the element of the template. It is either the original
16509  * element passed in, or the clone of the element if the `cloneAttachFn` is provided.
16510  *
16511  * After linking the view is not updated until after a call to $digest which typically is done by
16512  * Angular automatically.
16513  *
16514  * If you need access to the bound view, there are two ways to do it:
16515  *
16516  * - If you are not asking the linking function to clone the template, create the DOM element(s)
16517  *   before you send them to the compiler and keep this reference around.
16518  *   ```js
16519  *     var element = $compile('<p>{{total}}</p>')(scope);
16520  *   ```
16521  *
16522  * - if on the other hand, you need the element to be cloned, the view reference from the original
16523  *   example would not point to the clone, but rather to the original template that was cloned. In
16524  *   this case, you can access the clone via the cloneAttachFn:
16525  *   ```js
16526  *     var templateElement = angular.element('<p>{{total}}</p>'),
16527  *         scope = ....;
16528  *
16529  *     var clonedElement = $compile(templateElement)(scope, function(clonedElement, scope) {
16530  *       //attach the clone to DOM document at the right place
16531  *     });
16532  *
16533  *     //now we have reference to the cloned DOM via `clonedElement`
16534  *   ```
16535  *
16536  *
16537  * For information on how the compiler works, see the
16538  * {@link guide/compiler Angular HTML Compiler} section of the Developer Guide.
16539  */
16540
16541 var $compileMinErr = minErr('$compile');
16542
16543 /**
16544  * @ngdoc provider
16545  * @name $compileProvider
16546  *
16547  * @description
16548  */
16549 $CompileProvider.$inject = ['$provide', '$$sanitizeUriProvider'];
16550 function $CompileProvider($provide, $$sanitizeUriProvider) {
16551   var hasDirectives = {},
16552       Suffix = 'Directive',
16553       COMMENT_DIRECTIVE_REGEXP = /^\s*directive\:\s*([\w\-]+)\s+(.*)$/,
16554       CLASS_DIRECTIVE_REGEXP = /(([\w\-]+)(?:\:([^;]+))?;?)/,
16555       ALL_OR_NOTHING_ATTRS = makeMap('ngSrc,ngSrcset,src,srcset'),
16556       REQUIRE_PREFIX_REGEXP = /^(?:(\^\^?)?(\?)?(\^\^?)?)?/;
16557
16558   // Ref: http://developers.whatwg.org/webappapis.html#event-handler-idl-attributes
16559   // The assumption is that future DOM event attribute names will begin with
16560   // 'on' and be composed of only English letters.
16561   var EVENT_HANDLER_ATTR_REGEXP = /^(on[a-z]+|formaction)$/;
16562
16563   function parseIsolateBindings(scope, directiveName, isController) {
16564     var LOCAL_REGEXP = /^\s*([@&<]|=(\*?))(\??)\s*(\w*)\s*$/;
16565
16566     var bindings = {};
16567
16568     forEach(scope, function(definition, scopeName) {
16569       var match = definition.match(LOCAL_REGEXP);
16570
16571       if (!match) {
16572         throw $compileMinErr('iscp',
16573             "Invalid {3} for directive '{0}'." +
16574             " Definition: {... {1}: '{2}' ...}",
16575             directiveName, scopeName, definition,
16576             (isController ? "controller bindings definition" :
16577             "isolate scope definition"));
16578       }
16579
16580       bindings[scopeName] = {
16581         mode: match[1][0],
16582         collection: match[2] === '*',
16583         optional: match[3] === '?',
16584         attrName: match[4] || scopeName
16585       };
16586     });
16587
16588     return bindings;
16589   }
16590
16591   function parseDirectiveBindings(directive, directiveName) {
16592     var bindings = {
16593       isolateScope: null,
16594       bindToController: null
16595     };
16596     if (isObject(directive.scope)) {
16597       if (directive.bindToController === true) {
16598         bindings.bindToController = parseIsolateBindings(directive.scope,
16599                                                          directiveName, true);
16600         bindings.isolateScope = {};
16601       } else {
16602         bindings.isolateScope = parseIsolateBindings(directive.scope,
16603                                                      directiveName, false);
16604       }
16605     }
16606     if (isObject(directive.bindToController)) {
16607       bindings.bindToController =
16608           parseIsolateBindings(directive.bindToController, directiveName, true);
16609     }
16610     if (isObject(bindings.bindToController)) {
16611       var controller = directive.controller;
16612       var controllerAs = directive.controllerAs;
16613       if (!controller) {
16614         // There is no controller, there may or may not be a controllerAs property
16615         throw $compileMinErr('noctrl',
16616               "Cannot bind to controller without directive '{0}'s controller.",
16617               directiveName);
16618       } else if (!identifierForController(controller, controllerAs)) {
16619         // There is a controller, but no identifier or controllerAs property
16620         throw $compileMinErr('noident',
16621               "Cannot bind to controller without identifier for directive '{0}'.",
16622               directiveName);
16623       }
16624     }
16625     return bindings;
16626   }
16627
16628   function assertValidDirectiveName(name) {
16629     var letter = name.charAt(0);
16630     if (!letter || letter !== lowercase(letter)) {
16631       throw $compileMinErr('baddir', "Directive name '{0}' is invalid. The first character must be a lowercase letter", name);
16632     }
16633     if (name !== name.trim()) {
16634       throw $compileMinErr('baddir',
16635             "Directive name '{0}' is invalid. The name should not contain leading or trailing whitespaces",
16636             name);
16637     }
16638   }
16639
16640   /**
16641    * @ngdoc method
16642    * @name $compileProvider#directive
16643    * @kind function
16644    *
16645    * @description
16646    * Register a new directive with the compiler.
16647    *
16648    * @param {string|Object} name Name of the directive in camel-case (i.e. <code>ngBind</code> which
16649    *    will match as <code>ng-bind</code>), or an object map of directives where the keys are the
16650    *    names and the values are the factories.
16651    * @param {Function|Array} directiveFactory An injectable directive factory function. See the
16652    *    {@link guide/directive directive guide} and the {@link $compile compile API} for more info.
16653    * @returns {ng.$compileProvider} Self for chaining.
16654    */
16655    this.directive = function registerDirective(name, directiveFactory) {
16656     assertNotHasOwnProperty(name, 'directive');
16657     if (isString(name)) {
16658       assertValidDirectiveName(name);
16659       assertArg(directiveFactory, 'directiveFactory');
16660       if (!hasDirectives.hasOwnProperty(name)) {
16661         hasDirectives[name] = [];
16662         $provide.factory(name + Suffix, ['$injector', '$exceptionHandler',
16663           function($injector, $exceptionHandler) {
16664             var directives = [];
16665             forEach(hasDirectives[name], function(directiveFactory, index) {
16666               try {
16667                 var directive = $injector.invoke(directiveFactory);
16668                 if (isFunction(directive)) {
16669                   directive = { compile: valueFn(directive) };
16670                 } else if (!directive.compile && directive.link) {
16671                   directive.compile = valueFn(directive.link);
16672                 }
16673                 directive.priority = directive.priority || 0;
16674                 directive.index = index;
16675                 directive.name = directive.name || name;
16676                 directive.require = directive.require || (directive.controller && directive.name);
16677                 directive.restrict = directive.restrict || 'EA';
16678                 var bindings = directive.$$bindings =
16679                     parseDirectiveBindings(directive, directive.name);
16680                 if (isObject(bindings.isolateScope)) {
16681                   directive.$$isolateBindings = bindings.isolateScope;
16682                 }
16683                 directive.$$moduleName = directiveFactory.$$moduleName;
16684                 directives.push(directive);
16685               } catch (e) {
16686                 $exceptionHandler(e);
16687               }
16688             });
16689             return directives;
16690           }]);
16691       }
16692       hasDirectives[name].push(directiveFactory);
16693     } else {
16694       forEach(name, reverseParams(registerDirective));
16695     }
16696     return this;
16697   };
16698
16699   /**
16700    * @ngdoc method
16701    * @name $compileProvider#component
16702    * @module ng
16703    * @param {string} name Name of the component in camelCase (i.e. `myComp` which will match `<my-comp>`)
16704    * @param {Object} options Component definition object (a simplified
16705    *    {@link ng.$compile#directive-definition-object directive definition object}),
16706    *    with the following properties (all optional):
16707    *
16708    *    - `controller` – `{(string|function()=}` – controller constructor function that should be
16709    *      associated with newly created scope or the name of a {@link ng.$compile#-controller-
16710    *      registered controller} if passed as a string. An empty `noop` function by default.
16711    *    - `controllerAs` – `{string=}` – identifier name for to reference the controller in the component's scope.
16712    *      If present, the controller will be published to scope under the `controllerAs` name.
16713    *      If not present, this will default to be `$ctrl`.
16714    *    - `template` – `{string=|function()=}` – html template as a string or a function that
16715    *      returns an html template as a string which should be used as the contents of this component.
16716    *      Empty string by default.
16717    *
16718    *      If `template` is a function, then it is {@link auto.$injector#invoke injected} with
16719    *      the following locals:
16720    *
16721    *      - `$element` - Current element
16722    *      - `$attrs` - Current attributes object for the element
16723    *
16724    *    - `templateUrl` – `{string=|function()=}` – path or function that returns a path to an html
16725    *      template that should be used  as the contents of this component.
16726    *
16727    *      If `templateUrl` is a function, then it is {@link auto.$injector#invoke injected} with
16728    *      the following locals:
16729    *
16730    *      - `$element` - Current element
16731    *      - `$attrs` - Current attributes object for the element
16732    *
16733    *    - `bindings` – `{object=}` – defines bindings between DOM attributes and component properties.
16734    *      Component properties are always bound to the component controller and not to the scope.
16735    *      See {@link ng.$compile#-bindtocontroller- `bindToController`}.
16736    *    - `transclude` – `{boolean=}` – whether {@link $compile#transclusion content transclusion} is enabled.
16737    *      Disabled by default.
16738    *    - `$...` – `{function()=}` – additional annotations to provide to the directive factory function.
16739    *
16740    * @returns {ng.$compileProvider} the compile provider itself, for chaining of function calls.
16741    * @description
16742    * Register a **component definition** with the compiler. This is a shorthand for registering a special
16743    * type of directive, which represents a self-contained UI component in your application. Such components
16744    * are always isolated (i.e. `scope: {}`) and are always restricted to elements (i.e. `restrict: 'E'`).
16745    *
16746    * Component definitions are very simple and do not require as much configuration as defining general
16747    * directives. Component definitions usually consist only of a template and a controller backing it.
16748    *
16749    * In order to make the definition easier, components enforce best practices like use of `controllerAs`,
16750    * `bindToController`. They always have **isolate scope** and are restricted to elements.
16751    *
16752    * Here are a few examples of how you would usually define components:
16753    *
16754    * ```js
16755    *   var myMod = angular.module(...);
16756    *   myMod.component('myComp', {
16757    *     template: '<div>My name is {{$ctrl.name}}</div>',
16758    *     controller: function() {
16759    *       this.name = 'shahar';
16760    *     }
16761    *   });
16762    *
16763    *   myMod.component('myComp', {
16764    *     template: '<div>My name is {{$ctrl.name}}</div>',
16765    *     bindings: {name: '@'}
16766    *   });
16767    *
16768    *   myMod.component('myComp', {
16769    *     templateUrl: 'views/my-comp.html',
16770    *     controller: 'MyCtrl as ctrl',
16771    *     bindings: {name: '@'}
16772    *   });
16773    *
16774    * ```
16775    * For more examples, and an in-depth guide, see the {@link guide/component component guide}.
16776    *
16777    * <br />
16778    * See also {@link ng.$compileProvider#directive $compileProvider.directive()}.
16779    */
16780   this.component = function registerComponent(name, options) {
16781     var controller = options.controller || function() {};
16782
16783     function factory($injector) {
16784       function makeInjectable(fn) {
16785         if (isFunction(fn) || isArray(fn)) {
16786           return function(tElement, tAttrs) {
16787             return $injector.invoke(fn, this, {$element: tElement, $attrs: tAttrs});
16788           };
16789         } else {
16790           return fn;
16791         }
16792       }
16793
16794       var template = (!options.template && !options.templateUrl ? '' : options.template);
16795       return {
16796         controller: controller,
16797         controllerAs: identifierForController(options.controller) || options.controllerAs || '$ctrl',
16798         template: makeInjectable(template),
16799         templateUrl: makeInjectable(options.templateUrl),
16800         transclude: options.transclude,
16801         scope: {},
16802         bindToController: options.bindings || {},
16803         restrict: 'E',
16804         require: options.require
16805       };
16806     }
16807
16808     // Copy any annotation properties (starting with $) over to the factory function
16809     // These could be used by libraries such as the new component router
16810     forEach(options, function(val, key) {
16811       if (key.charAt(0) === '$') {
16812         factory[key] = val;
16813       }
16814     });
16815
16816     factory.$inject = ['$injector'];
16817
16818     return this.directive(name, factory);
16819   };
16820
16821
16822   /**
16823    * @ngdoc method
16824    * @name $compileProvider#aHrefSanitizationWhitelist
16825    * @kind function
16826    *
16827    * @description
16828    * Retrieves or overrides the default regular expression that is used for whitelisting of safe
16829    * urls during a[href] sanitization.
16830    *
16831    * The sanitization is a security measure aimed at preventing XSS attacks via html links.
16832    *
16833    * Any url about to be assigned to a[href] via data-binding is first normalized and turned into
16834    * an absolute url. Afterwards, the url is matched against the `aHrefSanitizationWhitelist`
16835    * regular expression. If a match is found, the original url is written into the dom. Otherwise,
16836    * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM.
16837    *
16838    * @param {RegExp=} regexp New regexp to whitelist urls with.
16839    * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
16840    *    chaining otherwise.
16841    */
16842   this.aHrefSanitizationWhitelist = function(regexp) {
16843     if (isDefined(regexp)) {
16844       $$sanitizeUriProvider.aHrefSanitizationWhitelist(regexp);
16845       return this;
16846     } else {
16847       return $$sanitizeUriProvider.aHrefSanitizationWhitelist();
16848     }
16849   };
16850
16851
16852   /**
16853    * @ngdoc method
16854    * @name $compileProvider#imgSrcSanitizationWhitelist
16855    * @kind function
16856    *
16857    * @description
16858    * Retrieves or overrides the default regular expression that is used for whitelisting of safe
16859    * urls during img[src] sanitization.
16860    *
16861    * The sanitization is a security measure aimed at prevent XSS attacks via html links.
16862    *
16863    * Any url about to be assigned to img[src] via data-binding is first normalized and turned into
16864    * an absolute url. Afterwards, the url is matched against the `imgSrcSanitizationWhitelist`
16865    * regular expression. If a match is found, the original url is written into the dom. Otherwise,
16866    * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM.
16867    *
16868    * @param {RegExp=} regexp New regexp to whitelist urls with.
16869    * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
16870    *    chaining otherwise.
16871    */
16872   this.imgSrcSanitizationWhitelist = function(regexp) {
16873     if (isDefined(regexp)) {
16874       $$sanitizeUriProvider.imgSrcSanitizationWhitelist(regexp);
16875       return this;
16876     } else {
16877       return $$sanitizeUriProvider.imgSrcSanitizationWhitelist();
16878     }
16879   };
16880
16881   /**
16882    * @ngdoc method
16883    * @name  $compileProvider#debugInfoEnabled
16884    *
16885    * @param {boolean=} enabled update the debugInfoEnabled state if provided, otherwise just return the
16886    * current debugInfoEnabled state
16887    * @returns {*} current value if used as getter or itself (chaining) if used as setter
16888    *
16889    * @kind function
16890    *
16891    * @description
16892    * Call this method to enable/disable various debug runtime information in the compiler such as adding
16893    * binding information and a reference to the current scope on to DOM elements.
16894    * If enabled, the compiler will add the following to DOM elements that have been bound to the scope
16895    * * `ng-binding` CSS class
16896    * * `$binding` data property containing an array of the binding expressions
16897    *
16898    * You may want to disable this in production for a significant performance boost. See
16899    * {@link guide/production#disabling-debug-data Disabling Debug Data} for more.
16900    *
16901    * The default value is true.
16902    */
16903   var debugInfoEnabled = true;
16904   this.debugInfoEnabled = function(enabled) {
16905     if (isDefined(enabled)) {
16906       debugInfoEnabled = enabled;
16907       return this;
16908     }
16909     return debugInfoEnabled;
16910   };
16911
16912   this.$get = [
16913             '$injector', '$interpolate', '$exceptionHandler', '$templateRequest', '$parse',
16914             '$controller', '$rootScope', '$sce', '$animate', '$$sanitizeUri',
16915     function($injector,   $interpolate,   $exceptionHandler,   $templateRequest,   $parse,
16916              $controller,   $rootScope,   $sce,   $animate,   $$sanitizeUri) {
16917
16918     var SIMPLE_ATTR_NAME = /^\w/;
16919     var specialAttrHolder = document.createElement('div');
16920     var Attributes = function(element, attributesToCopy) {
16921       if (attributesToCopy) {
16922         var keys = Object.keys(attributesToCopy);
16923         var i, l, key;
16924
16925         for (i = 0, l = keys.length; i < l; i++) {
16926           key = keys[i];
16927           this[key] = attributesToCopy[key];
16928         }
16929       } else {
16930         this.$attr = {};
16931       }
16932
16933       this.$$element = element;
16934     };
16935
16936     Attributes.prototype = {
16937       /**
16938        * @ngdoc method
16939        * @name $compile.directive.Attributes#$normalize
16940        * @kind function
16941        *
16942        * @description
16943        * Converts an attribute name (e.g. dash/colon/underscore-delimited string, optionally prefixed with `x-` or
16944        * `data-`) to its normalized, camelCase form.
16945        *
16946        * Also there is special case for Moz prefix starting with upper case letter.
16947        *
16948        * For further information check out the guide on {@link guide/directive#matching-directives Matching Directives}
16949        *
16950        * @param {string} name Name to normalize
16951        */
16952       $normalize: directiveNormalize,
16953
16954
16955       /**
16956        * @ngdoc method
16957        * @name $compile.directive.Attributes#$addClass
16958        * @kind function
16959        *
16960        * @description
16961        * Adds the CSS class value specified by the classVal parameter to the element. If animations
16962        * are enabled then an animation will be triggered for the class addition.
16963        *
16964        * @param {string} classVal The className value that will be added to the element
16965        */
16966       $addClass: function(classVal) {
16967         if (classVal && classVal.length > 0) {
16968           $animate.addClass(this.$$element, classVal);
16969         }
16970       },
16971
16972       /**
16973        * @ngdoc method
16974        * @name $compile.directive.Attributes#$removeClass
16975        * @kind function
16976        *
16977        * @description
16978        * Removes the CSS class value specified by the classVal parameter from the element. If
16979        * animations are enabled then an animation will be triggered for the class removal.
16980        *
16981        * @param {string} classVal The className value that will be removed from the element
16982        */
16983       $removeClass: function(classVal) {
16984         if (classVal && classVal.length > 0) {
16985           $animate.removeClass(this.$$element, classVal);
16986         }
16987       },
16988
16989       /**
16990        * @ngdoc method
16991        * @name $compile.directive.Attributes#$updateClass
16992        * @kind function
16993        *
16994        * @description
16995        * Adds and removes the appropriate CSS class values to the element based on the difference
16996        * between the new and old CSS class values (specified as newClasses and oldClasses).
16997        *
16998        * @param {string} newClasses The current CSS className value
16999        * @param {string} oldClasses The former CSS className value
17000        */
17001       $updateClass: function(newClasses, oldClasses) {
17002         var toAdd = tokenDifference(newClasses, oldClasses);
17003         if (toAdd && toAdd.length) {
17004           $animate.addClass(this.$$element, toAdd);
17005         }
17006
17007         var toRemove = tokenDifference(oldClasses, newClasses);
17008         if (toRemove && toRemove.length) {
17009           $animate.removeClass(this.$$element, toRemove);
17010         }
17011       },
17012
17013       /**
17014        * Set a normalized attribute on the element in a way such that all directives
17015        * can share the attribute. This function properly handles boolean attributes.
17016        * @param {string} key Normalized key. (ie ngAttribute)
17017        * @param {string|boolean} value The value to set. If `null` attribute will be deleted.
17018        * @param {boolean=} writeAttr If false, does not write the value to DOM element attribute.
17019        *     Defaults to true.
17020        * @param {string=} attrName Optional none normalized name. Defaults to key.
17021        */
17022       $set: function(key, value, writeAttr, attrName) {
17023         // TODO: decide whether or not to throw an error if "class"
17024         //is set through this function since it may cause $updateClass to
17025         //become unstable.
17026
17027         var node = this.$$element[0],
17028             booleanKey = getBooleanAttrName(node, key),
17029             aliasedKey = getAliasedAttrName(key),
17030             observer = key,
17031             nodeName;
17032
17033         if (booleanKey) {
17034           this.$$element.prop(key, value);
17035           attrName = booleanKey;
17036         } else if (aliasedKey) {
17037           this[aliasedKey] = value;
17038           observer = aliasedKey;
17039         }
17040
17041         this[key] = value;
17042
17043         // translate normalized key to actual key
17044         if (attrName) {
17045           this.$attr[key] = attrName;
17046         } else {
17047           attrName = this.$attr[key];
17048           if (!attrName) {
17049             this.$attr[key] = attrName = snake_case(key, '-');
17050           }
17051         }
17052
17053         nodeName = nodeName_(this.$$element);
17054
17055         if ((nodeName === 'a' && (key === 'href' || key === 'xlinkHref')) ||
17056             (nodeName === 'img' && key === 'src')) {
17057           // sanitize a[href] and img[src] values
17058           this[key] = value = $$sanitizeUri(value, key === 'src');
17059         } else if (nodeName === 'img' && key === 'srcset') {
17060           // sanitize img[srcset] values
17061           var result = "";
17062
17063           // first check if there are spaces because it's not the same pattern
17064           var trimmedSrcset = trim(value);
17065           //                (   999x   ,|   999w   ,|   ,|,   )
17066           var srcPattern = /(\s+\d+x\s*,|\s+\d+w\s*,|\s+,|,\s+)/;
17067           var pattern = /\s/.test(trimmedSrcset) ? srcPattern : /(,)/;
17068
17069           // split srcset into tuple of uri and descriptor except for the last item
17070           var rawUris = trimmedSrcset.split(pattern);
17071
17072           // for each tuples
17073           var nbrUrisWith2parts = Math.floor(rawUris.length / 2);
17074           for (var i = 0; i < nbrUrisWith2parts; i++) {
17075             var innerIdx = i * 2;
17076             // sanitize the uri
17077             result += $$sanitizeUri(trim(rawUris[innerIdx]), true);
17078             // add the descriptor
17079             result += (" " + trim(rawUris[innerIdx + 1]));
17080           }
17081
17082           // split the last item into uri and descriptor
17083           var lastTuple = trim(rawUris[i * 2]).split(/\s/);
17084
17085           // sanitize the last uri
17086           result += $$sanitizeUri(trim(lastTuple[0]), true);
17087
17088           // and add the last descriptor if any
17089           if (lastTuple.length === 2) {
17090             result += (" " + trim(lastTuple[1]));
17091           }
17092           this[key] = value = result;
17093         }
17094
17095         if (writeAttr !== false) {
17096           if (value === null || isUndefined(value)) {
17097             this.$$element.removeAttr(attrName);
17098           } else {
17099             if (SIMPLE_ATTR_NAME.test(attrName)) {
17100               this.$$element.attr(attrName, value);
17101             } else {
17102               setSpecialAttr(this.$$element[0], attrName, value);
17103             }
17104           }
17105         }
17106
17107         // fire observers
17108         var $$observers = this.$$observers;
17109         $$observers && forEach($$observers[observer], function(fn) {
17110           try {
17111             fn(value);
17112           } catch (e) {
17113             $exceptionHandler(e);
17114           }
17115         });
17116       },
17117
17118
17119       /**
17120        * @ngdoc method
17121        * @name $compile.directive.Attributes#$observe
17122        * @kind function
17123        *
17124        * @description
17125        * Observes an interpolated attribute.
17126        *
17127        * The observer function will be invoked once during the next `$digest` following
17128        * compilation. The observer is then invoked whenever the interpolated value
17129        * changes.
17130        *
17131        * @param {string} key Normalized key. (ie ngAttribute) .
17132        * @param {function(interpolatedValue)} fn Function that will be called whenever
17133                 the interpolated value of the attribute changes.
17134        *        See the {@link guide/interpolation#how-text-and-attribute-bindings-work Interpolation
17135        *        guide} for more info.
17136        * @returns {function()} Returns a deregistration function for this observer.
17137        */
17138       $observe: function(key, fn) {
17139         var attrs = this,
17140             $$observers = (attrs.$$observers || (attrs.$$observers = createMap())),
17141             listeners = ($$observers[key] || ($$observers[key] = []));
17142
17143         listeners.push(fn);
17144         $rootScope.$evalAsync(function() {
17145           if (!listeners.$$inter && attrs.hasOwnProperty(key) && !isUndefined(attrs[key])) {
17146             // no one registered attribute interpolation function, so lets call it manually
17147             fn(attrs[key]);
17148           }
17149         });
17150
17151         return function() {
17152           arrayRemove(listeners, fn);
17153         };
17154       }
17155     };
17156
17157     function setSpecialAttr(element, attrName, value) {
17158       // Attributes names that do not start with letters (such as `(click)`) cannot be set using `setAttribute`
17159       // so we have to jump through some hoops to get such an attribute
17160       // https://github.com/angular/angular.js/pull/13318
17161       specialAttrHolder.innerHTML = "<span " + attrName + ">";
17162       var attributes = specialAttrHolder.firstChild.attributes;
17163       var attribute = attributes[0];
17164       // We have to remove the attribute from its container element before we can add it to the destination element
17165       attributes.removeNamedItem(attribute.name);
17166       attribute.value = value;
17167       element.attributes.setNamedItem(attribute);
17168     }
17169
17170     function safeAddClass($element, className) {
17171       try {
17172         $element.addClass(className);
17173       } catch (e) {
17174         // ignore, since it means that we are trying to set class on
17175         // SVG element, where class name is read-only.
17176       }
17177     }
17178
17179
17180     var startSymbol = $interpolate.startSymbol(),
17181         endSymbol = $interpolate.endSymbol(),
17182         denormalizeTemplate = (startSymbol == '{{' && endSymbol  == '}}')
17183             ? identity
17184             : function denormalizeTemplate(template) {
17185               return template.replace(/\{\{/g, startSymbol).replace(/}}/g, endSymbol);
17186         },
17187         NG_ATTR_BINDING = /^ngAttr[A-Z]/;
17188     var MULTI_ELEMENT_DIR_RE = /^(.+)Start$/;
17189
17190     compile.$$addBindingInfo = debugInfoEnabled ? function $$addBindingInfo($element, binding) {
17191       var bindings = $element.data('$binding') || [];
17192
17193       if (isArray(binding)) {
17194         bindings = bindings.concat(binding);
17195       } else {
17196         bindings.push(binding);
17197       }
17198
17199       $element.data('$binding', bindings);
17200     } : noop;
17201
17202     compile.$$addBindingClass = debugInfoEnabled ? function $$addBindingClass($element) {
17203       safeAddClass($element, 'ng-binding');
17204     } : noop;
17205
17206     compile.$$addScopeInfo = debugInfoEnabled ? function $$addScopeInfo($element, scope, isolated, noTemplate) {
17207       var dataName = isolated ? (noTemplate ? '$isolateScopeNoTemplate' : '$isolateScope') : '$scope';
17208       $element.data(dataName, scope);
17209     } : noop;
17210
17211     compile.$$addScopeClass = debugInfoEnabled ? function $$addScopeClass($element, isolated) {
17212       safeAddClass($element, isolated ? 'ng-isolate-scope' : 'ng-scope');
17213     } : noop;
17214
17215     return compile;
17216
17217     //================================
17218
17219     function compile($compileNodes, transcludeFn, maxPriority, ignoreDirective,
17220                         previousCompileContext) {
17221       if (!($compileNodes instanceof jqLite)) {
17222         // jquery always rewraps, whereas we need to preserve the original selector so that we can
17223         // modify it.
17224         $compileNodes = jqLite($compileNodes);
17225       }
17226
17227       var NOT_EMPTY = /\S+/;
17228
17229       // We can not compile top level text elements since text nodes can be merged and we will
17230       // not be able to attach scope data to them, so we will wrap them in <span>
17231       for (var i = 0, len = $compileNodes.length; i < len; i++) {
17232         var domNode = $compileNodes[i];
17233
17234         if (domNode.nodeType === NODE_TYPE_TEXT && domNode.nodeValue.match(NOT_EMPTY) /* non-empty */) {
17235           jqLiteWrapNode(domNode, $compileNodes[i] = document.createElement('span'));
17236         }
17237       }
17238
17239       var compositeLinkFn =
17240               compileNodes($compileNodes, transcludeFn, $compileNodes,
17241                            maxPriority, ignoreDirective, previousCompileContext);
17242       compile.$$addScopeClass($compileNodes);
17243       var namespace = null;
17244       return function publicLinkFn(scope, cloneConnectFn, options) {
17245         assertArg(scope, 'scope');
17246
17247         if (previousCompileContext && previousCompileContext.needsNewScope) {
17248           // A parent directive did a replace and a directive on this element asked
17249           // for transclusion, which caused us to lose a layer of element on which
17250           // we could hold the new transclusion scope, so we will create it manually
17251           // here.
17252           scope = scope.$parent.$new();
17253         }
17254
17255         options = options || {};
17256         var parentBoundTranscludeFn = options.parentBoundTranscludeFn,
17257           transcludeControllers = options.transcludeControllers,
17258           futureParentElement = options.futureParentElement;
17259
17260         // When `parentBoundTranscludeFn` is passed, it is a
17261         // `controllersBoundTransclude` function (it was previously passed
17262         // as `transclude` to directive.link) so we must unwrap it to get
17263         // its `boundTranscludeFn`
17264         if (parentBoundTranscludeFn && parentBoundTranscludeFn.$$boundTransclude) {
17265           parentBoundTranscludeFn = parentBoundTranscludeFn.$$boundTransclude;
17266         }
17267
17268         if (!namespace) {
17269           namespace = detectNamespaceForChildElements(futureParentElement);
17270         }
17271         var $linkNode;
17272         if (namespace !== 'html') {
17273           // When using a directive with replace:true and templateUrl the $compileNodes
17274           // (or a child element inside of them)
17275           // might change, so we need to recreate the namespace adapted compileNodes
17276           // for call to the link function.
17277           // Note: This will already clone the nodes...
17278           $linkNode = jqLite(
17279             wrapTemplate(namespace, jqLite('<div>').append($compileNodes).html())
17280           );
17281         } else if (cloneConnectFn) {
17282           // important!!: we must call our jqLite.clone() since the jQuery one is trying to be smart
17283           // and sometimes changes the structure of the DOM.
17284           $linkNode = JQLitePrototype.clone.call($compileNodes);
17285         } else {
17286           $linkNode = $compileNodes;
17287         }
17288
17289         if (transcludeControllers) {
17290           for (var controllerName in transcludeControllers) {
17291             $linkNode.data('$' + controllerName + 'Controller', transcludeControllers[controllerName].instance);
17292           }
17293         }
17294
17295         compile.$$addScopeInfo($linkNode, scope);
17296
17297         if (cloneConnectFn) cloneConnectFn($linkNode, scope);
17298         if (compositeLinkFn) compositeLinkFn(scope, $linkNode, $linkNode, parentBoundTranscludeFn);
17299         return $linkNode;
17300       };
17301     }
17302
17303     function detectNamespaceForChildElements(parentElement) {
17304       // TODO: Make this detect MathML as well...
17305       var node = parentElement && parentElement[0];
17306       if (!node) {
17307         return 'html';
17308       } else {
17309         return nodeName_(node) !== 'foreignobject' && toString.call(node).match(/SVG/) ? 'svg' : 'html';
17310       }
17311     }
17312
17313     /**
17314      * Compile function matches each node in nodeList against the directives. Once all directives
17315      * for a particular node are collected their compile functions are executed. The compile
17316      * functions return values - the linking functions - are combined into a composite linking
17317      * function, which is the a linking function for the node.
17318      *
17319      * @param {NodeList} nodeList an array of nodes or NodeList to compile
17320      * @param {function(angular.Scope, cloneAttachFn=)} transcludeFn A linking function, where the
17321      *        scope argument is auto-generated to the new child of the transcluded parent scope.
17322      * @param {DOMElement=} $rootElement If the nodeList is the root of the compilation tree then
17323      *        the rootElement must be set the jqLite collection of the compile root. This is
17324      *        needed so that the jqLite collection items can be replaced with widgets.
17325      * @param {number=} maxPriority Max directive priority.
17326      * @returns {Function} A composite linking function of all of the matched directives or null.
17327      */
17328     function compileNodes(nodeList, transcludeFn, $rootElement, maxPriority, ignoreDirective,
17329                             previousCompileContext) {
17330       var linkFns = [],
17331           attrs, directives, nodeLinkFn, childNodes, childLinkFn, linkFnFound, nodeLinkFnFound;
17332
17333       for (var i = 0; i < nodeList.length; i++) {
17334         attrs = new Attributes();
17335
17336         // we must always refer to nodeList[i] since the nodes can be replaced underneath us.
17337         directives = collectDirectives(nodeList[i], [], attrs, i === 0 ? maxPriority : undefined,
17338                                         ignoreDirective);
17339
17340         nodeLinkFn = (directives.length)
17341             ? applyDirectivesToNode(directives, nodeList[i], attrs, transcludeFn, $rootElement,
17342                                       null, [], [], previousCompileContext)
17343             : null;
17344
17345         if (nodeLinkFn && nodeLinkFn.scope) {
17346           compile.$$addScopeClass(attrs.$$element);
17347         }
17348
17349         childLinkFn = (nodeLinkFn && nodeLinkFn.terminal ||
17350                       !(childNodes = nodeList[i].childNodes) ||
17351                       !childNodes.length)
17352             ? null
17353             : compileNodes(childNodes,
17354                  nodeLinkFn ? (
17355                   (nodeLinkFn.transcludeOnThisElement || !nodeLinkFn.templateOnThisElement)
17356                      && nodeLinkFn.transclude) : transcludeFn);
17357
17358         if (nodeLinkFn || childLinkFn) {
17359           linkFns.push(i, nodeLinkFn, childLinkFn);
17360           linkFnFound = true;
17361           nodeLinkFnFound = nodeLinkFnFound || nodeLinkFn;
17362         }
17363
17364         //use the previous context only for the first element in the virtual group
17365         previousCompileContext = null;
17366       }
17367
17368       // return a linking function if we have found anything, null otherwise
17369       return linkFnFound ? compositeLinkFn : null;
17370
17371       function compositeLinkFn(scope, nodeList, $rootElement, parentBoundTranscludeFn) {
17372         var nodeLinkFn, childLinkFn, node, childScope, i, ii, idx, childBoundTranscludeFn;
17373         var stableNodeList;
17374
17375
17376         if (nodeLinkFnFound) {
17377           // copy nodeList so that if a nodeLinkFn removes or adds an element at this DOM level our
17378           // offsets don't get screwed up
17379           var nodeListLength = nodeList.length;
17380           stableNodeList = new Array(nodeListLength);
17381
17382           // create a sparse array by only copying the elements which have a linkFn
17383           for (i = 0; i < linkFns.length; i+=3) {
17384             idx = linkFns[i];
17385             stableNodeList[idx] = nodeList[idx];
17386           }
17387         } else {
17388           stableNodeList = nodeList;
17389         }
17390
17391         for (i = 0, ii = linkFns.length; i < ii;) {
17392           node = stableNodeList[linkFns[i++]];
17393           nodeLinkFn = linkFns[i++];
17394           childLinkFn = linkFns[i++];
17395
17396           if (nodeLinkFn) {
17397             if (nodeLinkFn.scope) {
17398               childScope = scope.$new();
17399               compile.$$addScopeInfo(jqLite(node), childScope);
17400             } else {
17401               childScope = scope;
17402             }
17403
17404             if (nodeLinkFn.transcludeOnThisElement) {
17405               childBoundTranscludeFn = createBoundTranscludeFn(
17406                   scope, nodeLinkFn.transclude, parentBoundTranscludeFn);
17407
17408             } else if (!nodeLinkFn.templateOnThisElement && parentBoundTranscludeFn) {
17409               childBoundTranscludeFn = parentBoundTranscludeFn;
17410
17411             } else if (!parentBoundTranscludeFn && transcludeFn) {
17412               childBoundTranscludeFn = createBoundTranscludeFn(scope, transcludeFn);
17413
17414             } else {
17415               childBoundTranscludeFn = null;
17416             }
17417
17418             nodeLinkFn(childLinkFn, childScope, node, $rootElement, childBoundTranscludeFn);
17419
17420           } else if (childLinkFn) {
17421             childLinkFn(scope, node.childNodes, undefined, parentBoundTranscludeFn);
17422           }
17423         }
17424       }
17425     }
17426
17427     function createBoundTranscludeFn(scope, transcludeFn, previousBoundTranscludeFn) {
17428
17429       var boundTranscludeFn = function(transcludedScope, cloneFn, controllers, futureParentElement, containingScope) {
17430
17431         if (!transcludedScope) {
17432           transcludedScope = scope.$new(false, containingScope);
17433           transcludedScope.$$transcluded = true;
17434         }
17435
17436         return transcludeFn(transcludedScope, cloneFn, {
17437           parentBoundTranscludeFn: previousBoundTranscludeFn,
17438           transcludeControllers: controllers,
17439           futureParentElement: futureParentElement
17440         });
17441       };
17442
17443       // We need  to attach the transclusion slots onto the `boundTranscludeFn`
17444       // so that they are available inside the `controllersBoundTransclude` function
17445       var boundSlots = boundTranscludeFn.$$slots = createMap();
17446       for (var slotName in transcludeFn.$$slots) {
17447         if (transcludeFn.$$slots[slotName]) {
17448           boundSlots[slotName] = createBoundTranscludeFn(scope, transcludeFn.$$slots[slotName], previousBoundTranscludeFn);
17449         } else {
17450           boundSlots[slotName] = null;
17451         }
17452       }
17453
17454       return boundTranscludeFn;
17455     }
17456
17457     /**
17458      * Looks for directives on the given node and adds them to the directive collection which is
17459      * sorted.
17460      *
17461      * @param node Node to search.
17462      * @param directives An array to which the directives are added to. This array is sorted before
17463      *        the function returns.
17464      * @param attrs The shared attrs object which is used to populate the normalized attributes.
17465      * @param {number=} maxPriority Max directive priority.
17466      */
17467     function collectDirectives(node, directives, attrs, maxPriority, ignoreDirective) {
17468       var nodeType = node.nodeType,
17469           attrsMap = attrs.$attr,
17470           match,
17471           className;
17472
17473       switch (nodeType) {
17474         case NODE_TYPE_ELEMENT: /* Element */
17475           // use the node name: <directive>
17476           addDirective(directives,
17477               directiveNormalize(nodeName_(node)), 'E', maxPriority, ignoreDirective);
17478
17479           // iterate over the attributes
17480           for (var attr, name, nName, ngAttrName, value, isNgAttr, nAttrs = node.attributes,
17481                    j = 0, jj = nAttrs && nAttrs.length; j < jj; j++) {
17482             var attrStartName = false;
17483             var attrEndName = false;
17484
17485             attr = nAttrs[j];
17486             name = attr.name;
17487             value = trim(attr.value);
17488
17489             // support ngAttr attribute binding
17490             ngAttrName = directiveNormalize(name);
17491             if (isNgAttr = NG_ATTR_BINDING.test(ngAttrName)) {
17492               name = name.replace(PREFIX_REGEXP, '')
17493                 .substr(8).replace(/_(.)/g, function(match, letter) {
17494                   return letter.toUpperCase();
17495                 });
17496             }
17497
17498             var multiElementMatch = ngAttrName.match(MULTI_ELEMENT_DIR_RE);
17499             if (multiElementMatch && directiveIsMultiElement(multiElementMatch[1])) {
17500               attrStartName = name;
17501               attrEndName = name.substr(0, name.length - 5) + 'end';
17502               name = name.substr(0, name.length - 6);
17503             }
17504
17505             nName = directiveNormalize(name.toLowerCase());
17506             attrsMap[nName] = name;
17507             if (isNgAttr || !attrs.hasOwnProperty(nName)) {
17508                 attrs[nName] = value;
17509                 if (getBooleanAttrName(node, nName)) {
17510                   attrs[nName] = true; // presence means true
17511                 }
17512             }
17513             addAttrInterpolateDirective(node, directives, value, nName, isNgAttr);
17514             addDirective(directives, nName, 'A', maxPriority, ignoreDirective, attrStartName,
17515                           attrEndName);
17516           }
17517
17518           // use class as directive
17519           className = node.className;
17520           if (isObject(className)) {
17521               // Maybe SVGAnimatedString
17522               className = className.animVal;
17523           }
17524           if (isString(className) && className !== '') {
17525             while (match = CLASS_DIRECTIVE_REGEXP.exec(className)) {
17526               nName = directiveNormalize(match[2]);
17527               if (addDirective(directives, nName, 'C', maxPriority, ignoreDirective)) {
17528                 attrs[nName] = trim(match[3]);
17529               }
17530               className = className.substr(match.index + match[0].length);
17531             }
17532           }
17533           break;
17534         case NODE_TYPE_TEXT: /* Text Node */
17535           if (msie === 11) {
17536             // Workaround for #11781
17537             while (node.parentNode && node.nextSibling && node.nextSibling.nodeType === NODE_TYPE_TEXT) {
17538               node.nodeValue = node.nodeValue + node.nextSibling.nodeValue;
17539               node.parentNode.removeChild(node.nextSibling);
17540             }
17541           }
17542           addTextInterpolateDirective(directives, node.nodeValue);
17543           break;
17544         case NODE_TYPE_COMMENT: /* Comment */
17545           try {
17546             match = COMMENT_DIRECTIVE_REGEXP.exec(node.nodeValue);
17547             if (match) {
17548               nName = directiveNormalize(match[1]);
17549               if (addDirective(directives, nName, 'M', maxPriority, ignoreDirective)) {
17550                 attrs[nName] = trim(match[2]);
17551               }
17552             }
17553           } catch (e) {
17554             // turns out that under some circumstances IE9 throws errors when one attempts to read
17555             // comment's node value.
17556             // Just ignore it and continue. (Can't seem to reproduce in test case.)
17557           }
17558           break;
17559       }
17560
17561       directives.sort(byPriority);
17562       return directives;
17563     }
17564
17565     /**
17566      * Given a node with an directive-start it collects all of the siblings until it finds
17567      * directive-end.
17568      * @param node
17569      * @param attrStart
17570      * @param attrEnd
17571      * @returns {*}
17572      */
17573     function groupScan(node, attrStart, attrEnd) {
17574       var nodes = [];
17575       var depth = 0;
17576       if (attrStart && node.hasAttribute && node.hasAttribute(attrStart)) {
17577         do {
17578           if (!node) {
17579             throw $compileMinErr('uterdir',
17580                       "Unterminated attribute, found '{0}' but no matching '{1}' found.",
17581                       attrStart, attrEnd);
17582           }
17583           if (node.nodeType == NODE_TYPE_ELEMENT) {
17584             if (node.hasAttribute(attrStart)) depth++;
17585             if (node.hasAttribute(attrEnd)) depth--;
17586           }
17587           nodes.push(node);
17588           node = node.nextSibling;
17589         } while (depth > 0);
17590       } else {
17591         nodes.push(node);
17592       }
17593
17594       return jqLite(nodes);
17595     }
17596
17597     /**
17598      * Wrapper for linking function which converts normal linking function into a grouped
17599      * linking function.
17600      * @param linkFn
17601      * @param attrStart
17602      * @param attrEnd
17603      * @returns {Function}
17604      */
17605     function groupElementsLinkFnWrapper(linkFn, attrStart, attrEnd) {
17606       return function(scope, element, attrs, controllers, transcludeFn) {
17607         element = groupScan(element[0], attrStart, attrEnd);
17608         return linkFn(scope, element, attrs, controllers, transcludeFn);
17609       };
17610     }
17611
17612     /**
17613      * A function generator that is used to support both eager and lazy compilation
17614      * linking function.
17615      * @param eager
17616      * @param $compileNodes
17617      * @param transcludeFn
17618      * @param maxPriority
17619      * @param ignoreDirective
17620      * @param previousCompileContext
17621      * @returns {Function}
17622      */
17623     function compilationGenerator(eager, $compileNodes, transcludeFn, maxPriority, ignoreDirective, previousCompileContext) {
17624         if (eager) {
17625             return compile($compileNodes, transcludeFn, maxPriority, ignoreDirective, previousCompileContext);
17626         }
17627
17628         var compiled;
17629
17630         return function() {
17631             if (!compiled) {
17632                 compiled = compile($compileNodes, transcludeFn, maxPriority, ignoreDirective, previousCompileContext);
17633
17634                 // Null out all of these references in order to make them eligible for garbage collection
17635                 // since this is a potentially long lived closure
17636                 $compileNodes = transcludeFn = previousCompileContext = null;
17637             }
17638
17639             return compiled.apply(this, arguments);
17640         };
17641     }
17642
17643     /**
17644      * Once the directives have been collected, their compile functions are executed. This method
17645      * is responsible for inlining directive templates as well as terminating the application
17646      * of the directives if the terminal directive has been reached.
17647      *
17648      * @param {Array} directives Array of collected directives to execute their compile function.
17649      *        this needs to be pre-sorted by priority order.
17650      * @param {Node} compileNode The raw DOM node to apply the compile functions to
17651      * @param {Object} templateAttrs The shared attribute function
17652      * @param {function(angular.Scope, cloneAttachFn=)} transcludeFn A linking function, where the
17653      *                                                  scope argument is auto-generated to the new
17654      *                                                  child of the transcluded parent scope.
17655      * @param {JQLite} jqCollection If we are working on the root of the compile tree then this
17656      *                              argument has the root jqLite array so that we can replace nodes
17657      *                              on it.
17658      * @param {Object=} originalReplaceDirective An optional directive that will be ignored when
17659      *                                           compiling the transclusion.
17660      * @param {Array.<Function>} preLinkFns
17661      * @param {Array.<Function>} postLinkFns
17662      * @param {Object} previousCompileContext Context used for previous compilation of the current
17663      *                                        node
17664      * @returns {Function} linkFn
17665      */
17666     function applyDirectivesToNode(directives, compileNode, templateAttrs, transcludeFn,
17667                                    jqCollection, originalReplaceDirective, preLinkFns, postLinkFns,
17668                                    previousCompileContext) {
17669       previousCompileContext = previousCompileContext || {};
17670
17671       var terminalPriority = -Number.MAX_VALUE,
17672           newScopeDirective = previousCompileContext.newScopeDirective,
17673           controllerDirectives = previousCompileContext.controllerDirectives,
17674           newIsolateScopeDirective = previousCompileContext.newIsolateScopeDirective,
17675           templateDirective = previousCompileContext.templateDirective,
17676           nonTlbTranscludeDirective = previousCompileContext.nonTlbTranscludeDirective,
17677           hasTranscludeDirective = false,
17678           hasTemplate = false,
17679           hasElementTranscludeDirective = previousCompileContext.hasElementTranscludeDirective,
17680           $compileNode = templateAttrs.$$element = jqLite(compileNode),
17681           directive,
17682           directiveName,
17683           $template,
17684           replaceDirective = originalReplaceDirective,
17685           childTranscludeFn = transcludeFn,
17686           linkFn,
17687           didScanForMultipleTransclusion = false,
17688           mightHaveMultipleTransclusionError = false,
17689           directiveValue;
17690
17691       // executes all directives on the current element
17692       for (var i = 0, ii = directives.length; i < ii; i++) {
17693         directive = directives[i];
17694         var attrStart = directive.$$start;
17695         var attrEnd = directive.$$end;
17696
17697         // collect multiblock sections
17698         if (attrStart) {
17699           $compileNode = groupScan(compileNode, attrStart, attrEnd);
17700         }
17701         $template = undefined;
17702
17703         if (terminalPriority > directive.priority) {
17704           break; // prevent further processing of directives
17705         }
17706
17707         if (directiveValue = directive.scope) {
17708
17709           // skip the check for directives with async templates, we'll check the derived sync
17710           // directive when the template arrives
17711           if (!directive.templateUrl) {
17712             if (isObject(directiveValue)) {
17713               // This directive is trying to add an isolated scope.
17714               // Check that there is no scope of any kind already
17715               assertNoDuplicate('new/isolated scope', newIsolateScopeDirective || newScopeDirective,
17716                                 directive, $compileNode);
17717               newIsolateScopeDirective = directive;
17718             } else {
17719               // This directive is trying to add a child scope.
17720               // Check that there is no isolated scope already
17721               assertNoDuplicate('new/isolated scope', newIsolateScopeDirective, directive,
17722                                 $compileNode);
17723             }
17724           }
17725
17726           newScopeDirective = newScopeDirective || directive;
17727         }
17728
17729         directiveName = directive.name;
17730
17731         // If we encounter a condition that can result in transclusion on the directive,
17732         // then scan ahead in the remaining directives for others that may cause a multiple
17733         // transclusion error to be thrown during the compilation process.  If a matching directive
17734         // is found, then we know that when we encounter a transcluded directive, we need to eagerly
17735         // compile the `transclude` function rather than doing it lazily in order to throw
17736         // exceptions at the correct time
17737         if (!didScanForMultipleTransclusion && ((directive.replace && (directive.templateUrl || directive.template))
17738             || (directive.transclude && !directive.$$tlb))) {
17739                 var candidateDirective;
17740
17741                 for (var scanningIndex = i + 1; candidateDirective = directives[scanningIndex++];) {
17742                     if ((candidateDirective.transclude && !candidateDirective.$$tlb)
17743                         || (candidateDirective.replace && (candidateDirective.templateUrl || candidateDirective.template))) {
17744                         mightHaveMultipleTransclusionError = true;
17745                         break;
17746                     }
17747                 }
17748
17749                 didScanForMultipleTransclusion = true;
17750         }
17751
17752         if (!directive.templateUrl && directive.controller) {
17753           directiveValue = directive.controller;
17754           controllerDirectives = controllerDirectives || createMap();
17755           assertNoDuplicate("'" + directiveName + "' controller",
17756               controllerDirectives[directiveName], directive, $compileNode);
17757           controllerDirectives[directiveName] = directive;
17758         }
17759
17760         if (directiveValue = directive.transclude) {
17761           hasTranscludeDirective = true;
17762
17763           // Special case ngIf and ngRepeat so that we don't complain about duplicate transclusion.
17764           // This option should only be used by directives that know how to safely handle element transclusion,
17765           // where the transcluded nodes are added or replaced after linking.
17766           if (!directive.$$tlb) {
17767             assertNoDuplicate('transclusion', nonTlbTranscludeDirective, directive, $compileNode);
17768             nonTlbTranscludeDirective = directive;
17769           }
17770
17771           if (directiveValue == 'element') {
17772             hasElementTranscludeDirective = true;
17773             terminalPriority = directive.priority;
17774             $template = $compileNode;
17775             $compileNode = templateAttrs.$$element =
17776                 jqLite(document.createComment(' ' + directiveName + ': ' +
17777                                               templateAttrs[directiveName] + ' '));
17778             compileNode = $compileNode[0];
17779             replaceWith(jqCollection, sliceArgs($template), compileNode);
17780
17781             childTranscludeFn = compilationGenerator(mightHaveMultipleTransclusionError, $template, transcludeFn, terminalPriority,
17782                                         replaceDirective && replaceDirective.name, {
17783                                           // Don't pass in:
17784                                           // - controllerDirectives - otherwise we'll create duplicates controllers
17785                                           // - newIsolateScopeDirective or templateDirective - combining templates with
17786                                           //   element transclusion doesn't make sense.
17787                                           //
17788                                           // We need only nonTlbTranscludeDirective so that we prevent putting transclusion
17789                                           // on the same element more than once.
17790                                           nonTlbTranscludeDirective: nonTlbTranscludeDirective
17791                                         });
17792           } else {
17793
17794             var slots = createMap();
17795
17796             $template = jqLite(jqLiteClone(compileNode)).contents();
17797
17798             if (isObject(directiveValue)) {
17799
17800               // We have transclusion slots,
17801               // collect them up, compile them and store their transclusion functions
17802               $template = [];
17803
17804               var slotMap = createMap();
17805               var filledSlots = createMap();
17806
17807               // Parse the element selectors
17808               forEach(directiveValue, function(elementSelector, slotName) {
17809                 // If an element selector starts with a ? then it is optional
17810                 var optional = (elementSelector.charAt(0) === '?');
17811                 elementSelector = optional ? elementSelector.substring(1) : elementSelector;
17812
17813                 slotMap[elementSelector] = slotName;
17814
17815                 // We explicitly assign `null` since this implies that a slot was defined but not filled.
17816                 // Later when calling boundTransclusion functions with a slot name we only error if the
17817                 // slot is `undefined`
17818                 slots[slotName] = null;
17819
17820                 // filledSlots contains `true` for all slots that are either optional or have been
17821                 // filled. This is used to check that we have not missed any required slots
17822                 filledSlots[slotName] = optional;
17823               });
17824
17825               // Add the matching elements into their slot
17826               forEach($compileNode.contents(), function(node) {
17827                 var slotName = slotMap[directiveNormalize(nodeName_(node))];
17828                 if (slotName) {
17829                   filledSlots[slotName] = true;
17830                   slots[slotName] = slots[slotName] || [];
17831                   slots[slotName].push(node);
17832                 } else {
17833                   $template.push(node);
17834                 }
17835               });
17836
17837               // Check for required slots that were not filled
17838               forEach(filledSlots, function(filled, slotName) {
17839                 if (!filled) {
17840                   throw $compileMinErr('reqslot', 'Required transclusion slot `{0}` was not filled.', slotName);
17841                 }
17842               });
17843
17844               for (var slotName in slots) {
17845                 if (slots[slotName]) {
17846                   // Only define a transclusion function if the slot was filled
17847                   slots[slotName] = compilationGenerator(mightHaveMultipleTransclusionError, slots[slotName], transcludeFn);
17848                 }
17849               }
17850             }
17851
17852             $compileNode.empty(); // clear contents
17853             childTranscludeFn = compilationGenerator(mightHaveMultipleTransclusionError, $template, transcludeFn, undefined,
17854                 undefined, { needsNewScope: directive.$$isolateScope || directive.$$newScope});
17855             childTranscludeFn.$$slots = slots;
17856           }
17857         }
17858
17859         if (directive.template) {
17860           hasTemplate = true;
17861           assertNoDuplicate('template', templateDirective, directive, $compileNode);
17862           templateDirective = directive;
17863
17864           directiveValue = (isFunction(directive.template))
17865               ? directive.template($compileNode, templateAttrs)
17866               : directive.template;
17867
17868           directiveValue = denormalizeTemplate(directiveValue);
17869
17870           if (directive.replace) {
17871             replaceDirective = directive;
17872             if (jqLiteIsTextNode(directiveValue)) {
17873               $template = [];
17874             } else {
17875               $template = removeComments(wrapTemplate(directive.templateNamespace, trim(directiveValue)));
17876             }
17877             compileNode = $template[0];
17878
17879             if ($template.length != 1 || compileNode.nodeType !== NODE_TYPE_ELEMENT) {
17880               throw $compileMinErr('tplrt',
17881                   "Template for directive '{0}' must have exactly one root element. {1}",
17882                   directiveName, '');
17883             }
17884
17885             replaceWith(jqCollection, $compileNode, compileNode);
17886
17887             var newTemplateAttrs = {$attr: {}};
17888
17889             // combine directives from the original node and from the template:
17890             // - take the array of directives for this element
17891             // - split it into two parts, those that already applied (processed) and those that weren't (unprocessed)
17892             // - collect directives from the template and sort them by priority
17893             // - combine directives as: processed + template + unprocessed
17894             var templateDirectives = collectDirectives(compileNode, [], newTemplateAttrs);
17895             var unprocessedDirectives = directives.splice(i + 1, directives.length - (i + 1));
17896
17897             if (newIsolateScopeDirective || newScopeDirective) {
17898               // The original directive caused the current element to be replaced but this element
17899               // also needs to have a new scope, so we need to tell the template directives
17900               // that they would need to get their scope from further up, if they require transclusion
17901               markDirectiveScope(templateDirectives, newIsolateScopeDirective, newScopeDirective);
17902             }
17903             directives = directives.concat(templateDirectives).concat(unprocessedDirectives);
17904             mergeTemplateAttributes(templateAttrs, newTemplateAttrs);
17905
17906             ii = directives.length;
17907           } else {
17908             $compileNode.html(directiveValue);
17909           }
17910         }
17911
17912         if (directive.templateUrl) {
17913           hasTemplate = true;
17914           assertNoDuplicate('template', templateDirective, directive, $compileNode);
17915           templateDirective = directive;
17916
17917           if (directive.replace) {
17918             replaceDirective = directive;
17919           }
17920
17921           nodeLinkFn = compileTemplateUrl(directives.splice(i, directives.length - i), $compileNode,
17922               templateAttrs, jqCollection, hasTranscludeDirective && childTranscludeFn, preLinkFns, postLinkFns, {
17923                 controllerDirectives: controllerDirectives,
17924                 newScopeDirective: (newScopeDirective !== directive) && newScopeDirective,
17925                 newIsolateScopeDirective: newIsolateScopeDirective,
17926                 templateDirective: templateDirective,
17927                 nonTlbTranscludeDirective: nonTlbTranscludeDirective
17928               });
17929           ii = directives.length;
17930         } else if (directive.compile) {
17931           try {
17932             linkFn = directive.compile($compileNode, templateAttrs, childTranscludeFn);
17933             if (isFunction(linkFn)) {
17934               addLinkFns(null, linkFn, attrStart, attrEnd);
17935             } else if (linkFn) {
17936               addLinkFns(linkFn.pre, linkFn.post, attrStart, attrEnd);
17937             }
17938           } catch (e) {
17939             $exceptionHandler(e, startingTag($compileNode));
17940           }
17941         }
17942
17943         if (directive.terminal) {
17944           nodeLinkFn.terminal = true;
17945           terminalPriority = Math.max(terminalPriority, directive.priority);
17946         }
17947
17948       }
17949
17950       nodeLinkFn.scope = newScopeDirective && newScopeDirective.scope === true;
17951       nodeLinkFn.transcludeOnThisElement = hasTranscludeDirective;
17952       nodeLinkFn.templateOnThisElement = hasTemplate;
17953       nodeLinkFn.transclude = childTranscludeFn;
17954
17955       previousCompileContext.hasElementTranscludeDirective = hasElementTranscludeDirective;
17956
17957       // might be normal or delayed nodeLinkFn depending on if templateUrl is present
17958       return nodeLinkFn;
17959
17960       ////////////////////
17961
17962       function addLinkFns(pre, post, attrStart, attrEnd) {
17963         if (pre) {
17964           if (attrStart) pre = groupElementsLinkFnWrapper(pre, attrStart, attrEnd);
17965           pre.require = directive.require;
17966           pre.directiveName = directiveName;
17967           if (newIsolateScopeDirective === directive || directive.$$isolateScope) {
17968             pre = cloneAndAnnotateFn(pre, {isolateScope: true});
17969           }
17970           preLinkFns.push(pre);
17971         }
17972         if (post) {
17973           if (attrStart) post = groupElementsLinkFnWrapper(post, attrStart, attrEnd);
17974           post.require = directive.require;
17975           post.directiveName = directiveName;
17976           if (newIsolateScopeDirective === directive || directive.$$isolateScope) {
17977             post = cloneAndAnnotateFn(post, {isolateScope: true});
17978           }
17979           postLinkFns.push(post);
17980         }
17981       }
17982
17983
17984       function getControllers(directiveName, require, $element, elementControllers) {
17985         var value;
17986
17987         if (isString(require)) {
17988           var match = require.match(REQUIRE_PREFIX_REGEXP);
17989           var name = require.substring(match[0].length);
17990           var inheritType = match[1] || match[3];
17991           var optional = match[2] === '?';
17992
17993           //If only parents then start at the parent element
17994           if (inheritType === '^^') {
17995             $element = $element.parent();
17996           //Otherwise attempt getting the controller from elementControllers in case
17997           //the element is transcluded (and has no data) and to avoid .data if possible
17998           } else {
17999             value = elementControllers && elementControllers[name];
18000             value = value && value.instance;
18001           }
18002
18003           if (!value) {
18004             var dataName = '$' + name + 'Controller';
18005             value = inheritType ? $element.inheritedData(dataName) : $element.data(dataName);
18006           }
18007
18008           if (!value && !optional) {
18009             throw $compileMinErr('ctreq',
18010                 "Controller '{0}', required by directive '{1}', can't be found!",
18011                 name, directiveName);
18012           }
18013         } else if (isArray(require)) {
18014           value = [];
18015           for (var i = 0, ii = require.length; i < ii; i++) {
18016             value[i] = getControllers(directiveName, require[i], $element, elementControllers);
18017           }
18018         } else if (isObject(require)) {
18019           value = {};
18020           forEach(require, function(controller, property) {
18021             value[property] = getControllers(directiveName, controller, $element, elementControllers);
18022           });
18023         }
18024
18025         return value || null;
18026       }
18027
18028       function setupControllers($element, attrs, transcludeFn, controllerDirectives, isolateScope, scope) {
18029         var elementControllers = createMap();
18030         for (var controllerKey in controllerDirectives) {
18031           var directive = controllerDirectives[controllerKey];
18032           var locals = {
18033             $scope: directive === newIsolateScopeDirective || directive.$$isolateScope ? isolateScope : scope,
18034             $element: $element,
18035             $attrs: attrs,
18036             $transclude: transcludeFn
18037           };
18038
18039           var controller = directive.controller;
18040           if (controller == '@') {
18041             controller = attrs[directive.name];
18042           }
18043
18044           var controllerInstance = $controller(controller, locals, true, directive.controllerAs);
18045
18046           // For directives with element transclusion the element is a comment,
18047           // but jQuery .data doesn't support attaching data to comment nodes as it's hard to
18048           // clean up (http://bugs.jquery.com/ticket/8335).
18049           // Instead, we save the controllers for the element in a local hash and attach to .data
18050           // later, once we have the actual element.
18051           elementControllers[directive.name] = controllerInstance;
18052           if (!hasElementTranscludeDirective) {
18053             $element.data('$' + directive.name + 'Controller', controllerInstance.instance);
18054           }
18055         }
18056         return elementControllers;
18057       }
18058
18059       function nodeLinkFn(childLinkFn, scope, linkNode, $rootElement, boundTranscludeFn) {
18060         var i, ii, linkFn, isolateScope, controllerScope, elementControllers, transcludeFn, $element,
18061             attrs, removeScopeBindingWatches, removeControllerBindingWatches;
18062
18063         if (compileNode === linkNode) {
18064           attrs = templateAttrs;
18065           $element = templateAttrs.$$element;
18066         } else {
18067           $element = jqLite(linkNode);
18068           attrs = new Attributes($element, templateAttrs);
18069         }
18070
18071         controllerScope = scope;
18072         if (newIsolateScopeDirective) {
18073           isolateScope = scope.$new(true);
18074         } else if (newScopeDirective) {
18075           controllerScope = scope.$parent;
18076         }
18077
18078         if (boundTranscludeFn) {
18079           // track `boundTranscludeFn` so it can be unwrapped if `transcludeFn`
18080           // is later passed as `parentBoundTranscludeFn` to `publicLinkFn`
18081           transcludeFn = controllersBoundTransclude;
18082           transcludeFn.$$boundTransclude = boundTranscludeFn;
18083           // expose the slots on the `$transclude` function
18084           transcludeFn.isSlotFilled = function(slotName) {
18085             return !!boundTranscludeFn.$$slots[slotName];
18086           };
18087         }
18088
18089         if (controllerDirectives) {
18090           elementControllers = setupControllers($element, attrs, transcludeFn, controllerDirectives, isolateScope, scope);
18091         }
18092
18093         if (newIsolateScopeDirective) {
18094           // Initialize isolate scope bindings for new isolate scope directive.
18095           compile.$$addScopeInfo($element, isolateScope, true, !(templateDirective && (templateDirective === newIsolateScopeDirective ||
18096               templateDirective === newIsolateScopeDirective.$$originalDirective)));
18097           compile.$$addScopeClass($element, true);
18098           isolateScope.$$isolateBindings =
18099               newIsolateScopeDirective.$$isolateBindings;
18100           removeScopeBindingWatches = initializeDirectiveBindings(scope, attrs, isolateScope,
18101                                         isolateScope.$$isolateBindings,
18102                                         newIsolateScopeDirective);
18103           if (removeScopeBindingWatches) {
18104             isolateScope.$on('$destroy', removeScopeBindingWatches);
18105           }
18106         }
18107
18108         // Initialize bindToController bindings
18109         for (var name in elementControllers) {
18110           var controllerDirective = controllerDirectives[name];
18111           var controller = elementControllers[name];
18112           var bindings = controllerDirective.$$bindings.bindToController;
18113
18114           if (controller.identifier && bindings) {
18115             removeControllerBindingWatches =
18116               initializeDirectiveBindings(controllerScope, attrs, controller.instance, bindings, controllerDirective);
18117           }
18118
18119           var controllerResult = controller();
18120           if (controllerResult !== controller.instance) {
18121             // If the controller constructor has a return value, overwrite the instance
18122             // from setupControllers
18123             controller.instance = controllerResult;
18124             $element.data('$' + controllerDirective.name + 'Controller', controllerResult);
18125             removeControllerBindingWatches && removeControllerBindingWatches();
18126             removeControllerBindingWatches =
18127               initializeDirectiveBindings(controllerScope, attrs, controller.instance, bindings, controllerDirective);
18128           }
18129         }
18130
18131         // Bind the required controllers to the controller, if `require` is an object and `bindToController` is truthy
18132         forEach(controllerDirectives, function(controllerDirective, name) {
18133           var require = controllerDirective.require;
18134           if (controllerDirective.bindToController && !isArray(require) && isObject(require)) {
18135             extend(elementControllers[name].instance, getControllers(name, require, $element, elementControllers));
18136           }
18137         });
18138
18139         // Trigger the `$onInit` method on all controllers that have one
18140         forEach(elementControllers, function(controller) {
18141           if (isFunction(controller.instance.$onInit)) {
18142             controller.instance.$onInit();
18143           }
18144         });
18145
18146         // PRELINKING
18147         for (i = 0, ii = preLinkFns.length; i < ii; i++) {
18148           linkFn = preLinkFns[i];
18149           invokeLinkFn(linkFn,
18150               linkFn.isolateScope ? isolateScope : scope,
18151               $element,
18152               attrs,
18153               linkFn.require && getControllers(linkFn.directiveName, linkFn.require, $element, elementControllers),
18154               transcludeFn
18155           );
18156         }
18157
18158         // RECURSION
18159         // We only pass the isolate scope, if the isolate directive has a template,
18160         // otherwise the child elements do not belong to the isolate directive.
18161         var scopeToChild = scope;
18162         if (newIsolateScopeDirective && (newIsolateScopeDirective.template || newIsolateScopeDirective.templateUrl === null)) {
18163           scopeToChild = isolateScope;
18164         }
18165         childLinkFn && childLinkFn(scopeToChild, linkNode.childNodes, undefined, boundTranscludeFn);
18166
18167         // POSTLINKING
18168         for (i = postLinkFns.length - 1; i >= 0; i--) {
18169           linkFn = postLinkFns[i];
18170           invokeLinkFn(linkFn,
18171               linkFn.isolateScope ? isolateScope : scope,
18172               $element,
18173               attrs,
18174               linkFn.require && getControllers(linkFn.directiveName, linkFn.require, $element, elementControllers),
18175               transcludeFn
18176           );
18177         }
18178
18179         // This is the function that is injected as `$transclude`.
18180         // Note: all arguments are optional!
18181         function controllersBoundTransclude(scope, cloneAttachFn, futureParentElement, slotName) {
18182           var transcludeControllers;
18183           // No scope passed in:
18184           if (!isScope(scope)) {
18185             slotName = futureParentElement;
18186             futureParentElement = cloneAttachFn;
18187             cloneAttachFn = scope;
18188             scope = undefined;
18189           }
18190
18191           if (hasElementTranscludeDirective) {
18192             transcludeControllers = elementControllers;
18193           }
18194           if (!futureParentElement) {
18195             futureParentElement = hasElementTranscludeDirective ? $element.parent() : $element;
18196           }
18197           if (slotName) {
18198             // slotTranscludeFn can be one of three things:
18199             //  * a transclude function - a filled slot
18200             //  * `null` - an optional slot that was not filled
18201             //  * `undefined` - a slot that was not declared (i.e. invalid)
18202             var slotTranscludeFn = boundTranscludeFn.$$slots[slotName];
18203             if (slotTranscludeFn) {
18204               return slotTranscludeFn(scope, cloneAttachFn, transcludeControllers, futureParentElement, scopeToChild);
18205             } else if (isUndefined(slotTranscludeFn)) {
18206               throw $compileMinErr('noslot',
18207                'No parent directive that requires a transclusion with slot name "{0}". ' +
18208                'Element: {1}',
18209                slotName, startingTag($element));
18210             }
18211           } else {
18212             return boundTranscludeFn(scope, cloneAttachFn, transcludeControllers, futureParentElement, scopeToChild);
18213           }
18214         }
18215       }
18216     }
18217
18218     // Depending upon the context in which a directive finds itself it might need to have a new isolated
18219     // or child scope created. For instance:
18220     // * if the directive has been pulled into a template because another directive with a higher priority
18221     // asked for element transclusion
18222     // * if the directive itself asks for transclusion but it is at the root of a template and the original
18223     // element was replaced. See https://github.com/angular/angular.js/issues/12936
18224     function markDirectiveScope(directives, isolateScope, newScope) {
18225       for (var j = 0, jj = directives.length; j < jj; j++) {
18226         directives[j] = inherit(directives[j], {$$isolateScope: isolateScope, $$newScope: newScope});
18227       }
18228     }
18229
18230     /**
18231      * looks up the directive and decorates it with exception handling and proper parameters. We
18232      * call this the boundDirective.
18233      *
18234      * @param {string} name name of the directive to look up.
18235      * @param {string} location The directive must be found in specific format.
18236      *   String containing any of theses characters:
18237      *
18238      *   * `E`: element name
18239      *   * `A': attribute
18240      *   * `C`: class
18241      *   * `M`: comment
18242      * @returns {boolean} true if directive was added.
18243      */
18244     function addDirective(tDirectives, name, location, maxPriority, ignoreDirective, startAttrName,
18245                           endAttrName) {
18246       if (name === ignoreDirective) return null;
18247       var match = null;
18248       if (hasDirectives.hasOwnProperty(name)) {
18249         for (var directive, directives = $injector.get(name + Suffix),
18250             i = 0, ii = directives.length; i < ii; i++) {
18251           try {
18252             directive = directives[i];
18253             if ((isUndefined(maxPriority) || maxPriority > directive.priority) &&
18254                  directive.restrict.indexOf(location) != -1) {
18255               if (startAttrName) {
18256                 directive = inherit(directive, {$$start: startAttrName, $$end: endAttrName});
18257               }
18258               tDirectives.push(directive);
18259               match = directive;
18260             }
18261           } catch (e) { $exceptionHandler(e); }
18262         }
18263       }
18264       return match;
18265     }
18266
18267
18268     /**
18269      * looks up the directive and returns true if it is a multi-element directive,
18270      * and therefore requires DOM nodes between -start and -end markers to be grouped
18271      * together.
18272      *
18273      * @param {string} name name of the directive to look up.
18274      * @returns true if directive was registered as multi-element.
18275      */
18276     function directiveIsMultiElement(name) {
18277       if (hasDirectives.hasOwnProperty(name)) {
18278         for (var directive, directives = $injector.get(name + Suffix),
18279             i = 0, ii = directives.length; i < ii; i++) {
18280           directive = directives[i];
18281           if (directive.multiElement) {
18282             return true;
18283           }
18284         }
18285       }
18286       return false;
18287     }
18288
18289     /**
18290      * When the element is replaced with HTML template then the new attributes
18291      * on the template need to be merged with the existing attributes in the DOM.
18292      * The desired effect is to have both of the attributes present.
18293      *
18294      * @param {object} dst destination attributes (original DOM)
18295      * @param {object} src source attributes (from the directive template)
18296      */
18297     function mergeTemplateAttributes(dst, src) {
18298       var srcAttr = src.$attr,
18299           dstAttr = dst.$attr,
18300           $element = dst.$$element;
18301
18302       // reapply the old attributes to the new element
18303       forEach(dst, function(value, key) {
18304         if (key.charAt(0) != '$') {
18305           if (src[key] && src[key] !== value) {
18306             value += (key === 'style' ? ';' : ' ') + src[key];
18307           }
18308           dst.$set(key, value, true, srcAttr[key]);
18309         }
18310       });
18311
18312       // copy the new attributes on the old attrs object
18313       forEach(src, function(value, key) {
18314         if (key == 'class') {
18315           safeAddClass($element, value);
18316           dst['class'] = (dst['class'] ? dst['class'] + ' ' : '') + value;
18317         } else if (key == 'style') {
18318           $element.attr('style', $element.attr('style') + ';' + value);
18319           dst['style'] = (dst['style'] ? dst['style'] + ';' : '') + value;
18320           // `dst` will never contain hasOwnProperty as DOM parser won't let it.
18321           // You will get an "InvalidCharacterError: DOM Exception 5" error if you
18322           // have an attribute like "has-own-property" or "data-has-own-property", etc.
18323         } else if (key.charAt(0) != '$' && !dst.hasOwnProperty(key)) {
18324           dst[key] = value;
18325           dstAttr[key] = srcAttr[key];
18326         }
18327       });
18328     }
18329
18330
18331     function compileTemplateUrl(directives, $compileNode, tAttrs,
18332         $rootElement, childTranscludeFn, preLinkFns, postLinkFns, previousCompileContext) {
18333       var linkQueue = [],
18334           afterTemplateNodeLinkFn,
18335           afterTemplateChildLinkFn,
18336           beforeTemplateCompileNode = $compileNode[0],
18337           origAsyncDirective = directives.shift(),
18338           derivedSyncDirective = inherit(origAsyncDirective, {
18339             templateUrl: null, transclude: null, replace: null, $$originalDirective: origAsyncDirective
18340           }),
18341           templateUrl = (isFunction(origAsyncDirective.templateUrl))
18342               ? origAsyncDirective.templateUrl($compileNode, tAttrs)
18343               : origAsyncDirective.templateUrl,
18344           templateNamespace = origAsyncDirective.templateNamespace;
18345
18346       $compileNode.empty();
18347
18348       $templateRequest(templateUrl)
18349         .then(function(content) {
18350           var compileNode, tempTemplateAttrs, $template, childBoundTranscludeFn;
18351
18352           content = denormalizeTemplate(content);
18353
18354           if (origAsyncDirective.replace) {
18355             if (jqLiteIsTextNode(content)) {
18356               $template = [];
18357             } else {
18358               $template = removeComments(wrapTemplate(templateNamespace, trim(content)));
18359             }
18360             compileNode = $template[0];
18361
18362             if ($template.length != 1 || compileNode.nodeType !== NODE_TYPE_ELEMENT) {
18363               throw $compileMinErr('tplrt',
18364                   "Template for directive '{0}' must have exactly one root element. {1}",
18365                   origAsyncDirective.name, templateUrl);
18366             }
18367
18368             tempTemplateAttrs = {$attr: {}};
18369             replaceWith($rootElement, $compileNode, compileNode);
18370             var templateDirectives = collectDirectives(compileNode, [], tempTemplateAttrs);
18371
18372             if (isObject(origAsyncDirective.scope)) {
18373               // the original directive that caused the template to be loaded async required
18374               // an isolate scope
18375               markDirectiveScope(templateDirectives, true);
18376             }
18377             directives = templateDirectives.concat(directives);
18378             mergeTemplateAttributes(tAttrs, tempTemplateAttrs);
18379           } else {
18380             compileNode = beforeTemplateCompileNode;
18381             $compileNode.html(content);
18382           }
18383
18384           directives.unshift(derivedSyncDirective);
18385
18386           afterTemplateNodeLinkFn = applyDirectivesToNode(directives, compileNode, tAttrs,
18387               childTranscludeFn, $compileNode, origAsyncDirective, preLinkFns, postLinkFns,
18388               previousCompileContext);
18389           forEach($rootElement, function(node, i) {
18390             if (node == compileNode) {
18391               $rootElement[i] = $compileNode[0];
18392             }
18393           });
18394           afterTemplateChildLinkFn = compileNodes($compileNode[0].childNodes, childTranscludeFn);
18395
18396           while (linkQueue.length) {
18397             var scope = linkQueue.shift(),
18398                 beforeTemplateLinkNode = linkQueue.shift(),
18399                 linkRootElement = linkQueue.shift(),
18400                 boundTranscludeFn = linkQueue.shift(),
18401                 linkNode = $compileNode[0];
18402
18403             if (scope.$$destroyed) continue;
18404
18405             if (beforeTemplateLinkNode !== beforeTemplateCompileNode) {
18406               var oldClasses = beforeTemplateLinkNode.className;
18407
18408               if (!(previousCompileContext.hasElementTranscludeDirective &&
18409                   origAsyncDirective.replace)) {
18410                 // it was cloned therefore we have to clone as well.
18411                 linkNode = jqLiteClone(compileNode);
18412               }
18413               replaceWith(linkRootElement, jqLite(beforeTemplateLinkNode), linkNode);
18414
18415               // Copy in CSS classes from original node
18416               safeAddClass(jqLite(linkNode), oldClasses);
18417             }
18418             if (afterTemplateNodeLinkFn.transcludeOnThisElement) {
18419               childBoundTranscludeFn = createBoundTranscludeFn(scope, afterTemplateNodeLinkFn.transclude, boundTranscludeFn);
18420             } else {
18421               childBoundTranscludeFn = boundTranscludeFn;
18422             }
18423             afterTemplateNodeLinkFn(afterTemplateChildLinkFn, scope, linkNode, $rootElement,
18424               childBoundTranscludeFn);
18425           }
18426           linkQueue = null;
18427         });
18428
18429       return function delayedNodeLinkFn(ignoreChildLinkFn, scope, node, rootElement, boundTranscludeFn) {
18430         var childBoundTranscludeFn = boundTranscludeFn;
18431         if (scope.$$destroyed) return;
18432         if (linkQueue) {
18433           linkQueue.push(scope,
18434                          node,
18435                          rootElement,
18436                          childBoundTranscludeFn);
18437         } else {
18438           if (afterTemplateNodeLinkFn.transcludeOnThisElement) {
18439             childBoundTranscludeFn = createBoundTranscludeFn(scope, afterTemplateNodeLinkFn.transclude, boundTranscludeFn);
18440           }
18441           afterTemplateNodeLinkFn(afterTemplateChildLinkFn, scope, node, rootElement, childBoundTranscludeFn);
18442         }
18443       };
18444     }
18445
18446
18447     /**
18448      * Sorting function for bound directives.
18449      */
18450     function byPriority(a, b) {
18451       var diff = b.priority - a.priority;
18452       if (diff !== 0) return diff;
18453       if (a.name !== b.name) return (a.name < b.name) ? -1 : 1;
18454       return a.index - b.index;
18455     }
18456
18457     function assertNoDuplicate(what, previousDirective, directive, element) {
18458
18459       function wrapModuleNameIfDefined(moduleName) {
18460         return moduleName ?
18461           (' (module: ' + moduleName + ')') :
18462           '';
18463       }
18464
18465       if (previousDirective) {
18466         throw $compileMinErr('multidir', 'Multiple directives [{0}{1}, {2}{3}] asking for {4} on: {5}',
18467             previousDirective.name, wrapModuleNameIfDefined(previousDirective.$$moduleName),
18468             directive.name, wrapModuleNameIfDefined(directive.$$moduleName), what, startingTag(element));
18469       }
18470     }
18471
18472
18473     function addTextInterpolateDirective(directives, text) {
18474       var interpolateFn = $interpolate(text, true);
18475       if (interpolateFn) {
18476         directives.push({
18477           priority: 0,
18478           compile: function textInterpolateCompileFn(templateNode) {
18479             var templateNodeParent = templateNode.parent(),
18480                 hasCompileParent = !!templateNodeParent.length;
18481
18482             // When transcluding a template that has bindings in the root
18483             // we don't have a parent and thus need to add the class during linking fn.
18484             if (hasCompileParent) compile.$$addBindingClass(templateNodeParent);
18485
18486             return function textInterpolateLinkFn(scope, node) {
18487               var parent = node.parent();
18488               if (!hasCompileParent) compile.$$addBindingClass(parent);
18489               compile.$$addBindingInfo(parent, interpolateFn.expressions);
18490               scope.$watch(interpolateFn, function interpolateFnWatchAction(value) {
18491                 node[0].nodeValue = value;
18492               });
18493             };
18494           }
18495         });
18496       }
18497     }
18498
18499
18500     function wrapTemplate(type, template) {
18501       type = lowercase(type || 'html');
18502       switch (type) {
18503       case 'svg':
18504       case 'math':
18505         var wrapper = document.createElement('div');
18506         wrapper.innerHTML = '<' + type + '>' + template + '</' + type + '>';
18507         return wrapper.childNodes[0].childNodes;
18508       default:
18509         return template;
18510       }
18511     }
18512
18513
18514     function getTrustedContext(node, attrNormalizedName) {
18515       if (attrNormalizedName == "srcdoc") {
18516         return $sce.HTML;
18517       }
18518       var tag = nodeName_(node);
18519       // maction[xlink:href] can source SVG.  It's not limited to <maction>.
18520       if (attrNormalizedName == "xlinkHref" ||
18521           (tag == "form" && attrNormalizedName == "action") ||
18522           (tag != "img" && (attrNormalizedName == "src" ||
18523                             attrNormalizedName == "ngSrc"))) {
18524         return $sce.RESOURCE_URL;
18525       }
18526     }
18527
18528
18529     function addAttrInterpolateDirective(node, directives, value, name, allOrNothing) {
18530       var trustedContext = getTrustedContext(node, name);
18531       allOrNothing = ALL_OR_NOTHING_ATTRS[name] || allOrNothing;
18532
18533       var interpolateFn = $interpolate(value, true, trustedContext, allOrNothing);
18534
18535       // no interpolation found -> ignore
18536       if (!interpolateFn) return;
18537
18538
18539       if (name === "multiple" && nodeName_(node) === "select") {
18540         throw $compileMinErr("selmulti",
18541             "Binding to the 'multiple' attribute is not supported. Element: {0}",
18542             startingTag(node));
18543       }
18544
18545       directives.push({
18546         priority: 100,
18547         compile: function() {
18548             return {
18549               pre: function attrInterpolatePreLinkFn(scope, element, attr) {
18550                 var $$observers = (attr.$$observers || (attr.$$observers = createMap()));
18551
18552                 if (EVENT_HANDLER_ATTR_REGEXP.test(name)) {
18553                   throw $compileMinErr('nodomevents',
18554                       "Interpolations for HTML DOM event attributes are disallowed.  Please use the " +
18555                           "ng- versions (such as ng-click instead of onclick) instead.");
18556                 }
18557
18558                 // If the attribute has changed since last $interpolate()ed
18559                 var newValue = attr[name];
18560                 if (newValue !== value) {
18561                   // we need to interpolate again since the attribute value has been updated
18562                   // (e.g. by another directive's compile function)
18563                   // ensure unset/empty values make interpolateFn falsy
18564                   interpolateFn = newValue && $interpolate(newValue, true, trustedContext, allOrNothing);
18565                   value = newValue;
18566                 }
18567
18568                 // if attribute was updated so that there is no interpolation going on we don't want to
18569                 // register any observers
18570                 if (!interpolateFn) return;
18571
18572                 // initialize attr object so that it's ready in case we need the value for isolate
18573                 // scope initialization, otherwise the value would not be available from isolate
18574                 // directive's linking fn during linking phase
18575                 attr[name] = interpolateFn(scope);
18576
18577                 ($$observers[name] || ($$observers[name] = [])).$$inter = true;
18578                 (attr.$$observers && attr.$$observers[name].$$scope || scope).
18579                   $watch(interpolateFn, function interpolateFnWatchAction(newValue, oldValue) {
18580                     //special case for class attribute addition + removal
18581                     //so that class changes can tap into the animation
18582                     //hooks provided by the $animate service. Be sure to
18583                     //skip animations when the first digest occurs (when
18584                     //both the new and the old values are the same) since
18585                     //the CSS classes are the non-interpolated values
18586                     if (name === 'class' && newValue != oldValue) {
18587                       attr.$updateClass(newValue, oldValue);
18588                     } else {
18589                       attr.$set(name, newValue);
18590                     }
18591                   });
18592               }
18593             };
18594           }
18595       });
18596     }
18597
18598
18599     /**
18600      * This is a special jqLite.replaceWith, which can replace items which
18601      * have no parents, provided that the containing jqLite collection is provided.
18602      *
18603      * @param {JqLite=} $rootElement The root of the compile tree. Used so that we can replace nodes
18604      *                               in the root of the tree.
18605      * @param {JqLite} elementsToRemove The jqLite element which we are going to replace. We keep
18606      *                                  the shell, but replace its DOM node reference.
18607      * @param {Node} newNode The new DOM node.
18608      */
18609     function replaceWith($rootElement, elementsToRemove, newNode) {
18610       var firstElementToRemove = elementsToRemove[0],
18611           removeCount = elementsToRemove.length,
18612           parent = firstElementToRemove.parentNode,
18613           i, ii;
18614
18615       if ($rootElement) {
18616         for (i = 0, ii = $rootElement.length; i < ii; i++) {
18617           if ($rootElement[i] == firstElementToRemove) {
18618             $rootElement[i++] = newNode;
18619             for (var j = i, j2 = j + removeCount - 1,
18620                      jj = $rootElement.length;
18621                  j < jj; j++, j2++) {
18622               if (j2 < jj) {
18623                 $rootElement[j] = $rootElement[j2];
18624               } else {
18625                 delete $rootElement[j];
18626               }
18627             }
18628             $rootElement.length -= removeCount - 1;
18629
18630             // If the replaced element is also the jQuery .context then replace it
18631             // .context is a deprecated jQuery api, so we should set it only when jQuery set it
18632             // http://api.jquery.com/context/
18633             if ($rootElement.context === firstElementToRemove) {
18634               $rootElement.context = newNode;
18635             }
18636             break;
18637           }
18638         }
18639       }
18640
18641       if (parent) {
18642         parent.replaceChild(newNode, firstElementToRemove);
18643       }
18644
18645       // Append all the `elementsToRemove` to a fragment. This will...
18646       // - remove them from the DOM
18647       // - allow them to still be traversed with .nextSibling
18648       // - allow a single fragment.qSA to fetch all elements being removed
18649       var fragment = document.createDocumentFragment();
18650       for (i = 0; i < removeCount; i++) {
18651         fragment.appendChild(elementsToRemove[i]);
18652       }
18653
18654       if (jqLite.hasData(firstElementToRemove)) {
18655         // Copy over user data (that includes Angular's $scope etc.). Don't copy private
18656         // data here because there's no public interface in jQuery to do that and copying over
18657         // event listeners (which is the main use of private data) wouldn't work anyway.
18658         jqLite.data(newNode, jqLite.data(firstElementToRemove));
18659
18660         // Remove $destroy event listeners from `firstElementToRemove`
18661         jqLite(firstElementToRemove).off('$destroy');
18662       }
18663
18664       // Cleanup any data/listeners on the elements and children.
18665       // This includes invoking the $destroy event on any elements with listeners.
18666       jqLite.cleanData(fragment.querySelectorAll('*'));
18667
18668       // Update the jqLite collection to only contain the `newNode`
18669       for (i = 1; i < removeCount; i++) {
18670         delete elementsToRemove[i];
18671       }
18672       elementsToRemove[0] = newNode;
18673       elementsToRemove.length = 1;
18674     }
18675
18676
18677     function cloneAndAnnotateFn(fn, annotation) {
18678       return extend(function() { return fn.apply(null, arguments); }, fn, annotation);
18679     }
18680
18681
18682     function invokeLinkFn(linkFn, scope, $element, attrs, controllers, transcludeFn) {
18683       try {
18684         linkFn(scope, $element, attrs, controllers, transcludeFn);
18685       } catch (e) {
18686         $exceptionHandler(e, startingTag($element));
18687       }
18688     }
18689
18690
18691     // Set up $watches for isolate scope and controller bindings. This process
18692     // only occurs for isolate scopes and new scopes with controllerAs.
18693     function initializeDirectiveBindings(scope, attrs, destination, bindings, directive) {
18694       var removeWatchCollection = [];
18695       forEach(bindings, function(definition, scopeName) {
18696         var attrName = definition.attrName,
18697         optional = definition.optional,
18698         mode = definition.mode, // @, =, or &
18699         lastValue,
18700         parentGet, parentSet, compare, removeWatch;
18701
18702         switch (mode) {
18703
18704           case '@':
18705             if (!optional && !hasOwnProperty.call(attrs, attrName)) {
18706               destination[scopeName] = attrs[attrName] = void 0;
18707             }
18708             attrs.$observe(attrName, function(value) {
18709               if (isString(value)) {
18710                 destination[scopeName] = value;
18711               }
18712             });
18713             attrs.$$observers[attrName].$$scope = scope;
18714             lastValue = attrs[attrName];
18715             if (isString(lastValue)) {
18716               // If the attribute has been provided then we trigger an interpolation to ensure
18717               // the value is there for use in the link fn
18718               destination[scopeName] = $interpolate(lastValue)(scope);
18719             } else if (isBoolean(lastValue)) {
18720               // If the attributes is one of the BOOLEAN_ATTR then Angular will have converted
18721               // the value to boolean rather than a string, so we special case this situation
18722               destination[scopeName] = lastValue;
18723             }
18724             break;
18725
18726           case '=':
18727             if (!hasOwnProperty.call(attrs, attrName)) {
18728               if (optional) break;
18729               attrs[attrName] = void 0;
18730             }
18731             if (optional && !attrs[attrName]) break;
18732
18733             parentGet = $parse(attrs[attrName]);
18734             if (parentGet.literal) {
18735               compare = equals;
18736             } else {
18737               compare = function(a, b) { return a === b || (a !== a && b !== b); };
18738             }
18739             parentSet = parentGet.assign || function() {
18740               // reset the change, or we will throw this exception on every $digest
18741               lastValue = destination[scopeName] = parentGet(scope);
18742               throw $compileMinErr('nonassign',
18743                   "Expression '{0}' in attribute '{1}' used with directive '{2}' is non-assignable!",
18744                   attrs[attrName], attrName, directive.name);
18745             };
18746             lastValue = destination[scopeName] = parentGet(scope);
18747             var parentValueWatch = function parentValueWatch(parentValue) {
18748               if (!compare(parentValue, destination[scopeName])) {
18749                 // we are out of sync and need to copy
18750                 if (!compare(parentValue, lastValue)) {
18751                   // parent changed and it has precedence
18752                   destination[scopeName] = parentValue;
18753                 } else {
18754                   // if the parent can be assigned then do so
18755                   parentSet(scope, parentValue = destination[scopeName]);
18756                 }
18757               }
18758               return lastValue = parentValue;
18759             };
18760             parentValueWatch.$stateful = true;
18761             if (definition.collection) {
18762               removeWatch = scope.$watchCollection(attrs[attrName], parentValueWatch);
18763             } else {
18764               removeWatch = scope.$watch($parse(attrs[attrName], parentValueWatch), null, parentGet.literal);
18765             }
18766             removeWatchCollection.push(removeWatch);
18767             break;
18768
18769           case '<':
18770             if (!hasOwnProperty.call(attrs, attrName)) {
18771               if (optional) break;
18772               attrs[attrName] = void 0;
18773             }
18774             if (optional && !attrs[attrName]) break;
18775
18776             parentGet = $parse(attrs[attrName]);
18777
18778             destination[scopeName] = parentGet(scope);
18779
18780             removeWatch = scope.$watch(parentGet, function parentValueWatchAction(newParentValue) {
18781               destination[scopeName] = newParentValue;
18782             }, parentGet.literal);
18783
18784             removeWatchCollection.push(removeWatch);
18785             break;
18786
18787           case '&':
18788             // Don't assign Object.prototype method to scope
18789             parentGet = attrs.hasOwnProperty(attrName) ? $parse(attrs[attrName]) : noop;
18790
18791             // Don't assign noop to destination if expression is not valid
18792             if (parentGet === noop && optional) break;
18793
18794             destination[scopeName] = function(locals) {
18795               return parentGet(scope, locals);
18796             };
18797             break;
18798         }
18799       });
18800
18801       return removeWatchCollection.length && function removeWatches() {
18802         for (var i = 0, ii = removeWatchCollection.length; i < ii; ++i) {
18803           removeWatchCollection[i]();
18804         }
18805       };
18806     }
18807   }];
18808 }
18809
18810 var PREFIX_REGEXP = /^((?:x|data)[\:\-_])/i;
18811 /**
18812  * Converts all accepted directives format into proper directive name.
18813  * @param name Name to normalize
18814  */
18815 function directiveNormalize(name) {
18816   return camelCase(name.replace(PREFIX_REGEXP, ''));
18817 }
18818
18819 /**
18820  * @ngdoc type
18821  * @name $compile.directive.Attributes
18822  *
18823  * @description
18824  * A shared object between directive compile / linking functions which contains normalized DOM
18825  * element attributes. The values reflect current binding state `{{ }}`. The normalization is
18826  * needed since all of these are treated as equivalent in Angular:
18827  *
18828  * ```
18829  *    <span ng:bind="a" ng-bind="a" data-ng-bind="a" x-ng-bind="a">
18830  * ```
18831  */
18832
18833 /**
18834  * @ngdoc property
18835  * @name $compile.directive.Attributes#$attr
18836  *
18837  * @description
18838  * A map of DOM element attribute names to the normalized name. This is
18839  * needed to do reverse lookup from normalized name back to actual name.
18840  */
18841
18842
18843 /**
18844  * @ngdoc method
18845  * @name $compile.directive.Attributes#$set
18846  * @kind function
18847  *
18848  * @description
18849  * Set DOM element attribute value.
18850  *
18851  *
18852  * @param {string} name Normalized element attribute name of the property to modify. The name is
18853  *          reverse-translated using the {@link ng.$compile.directive.Attributes#$attr $attr}
18854  *          property to the original name.
18855  * @param {string} value Value to set the attribute to. The value can be an interpolated string.
18856  */
18857
18858
18859
18860 /**
18861  * Closure compiler type information
18862  */
18863
18864 function nodesetLinkingFn(
18865   /* angular.Scope */ scope,
18866   /* NodeList */ nodeList,
18867   /* Element */ rootElement,
18868   /* function(Function) */ boundTranscludeFn
18869 ) {}
18870
18871 function directiveLinkingFn(
18872   /* nodesetLinkingFn */ nodesetLinkingFn,
18873   /* angular.Scope */ scope,
18874   /* Node */ node,
18875   /* Element */ rootElement,
18876   /* function(Function) */ boundTranscludeFn
18877 ) {}
18878
18879 function tokenDifference(str1, str2) {
18880   var values = '',
18881       tokens1 = str1.split(/\s+/),
18882       tokens2 = str2.split(/\s+/);
18883
18884   outer:
18885   for (var i = 0; i < tokens1.length; i++) {
18886     var token = tokens1[i];
18887     for (var j = 0; j < tokens2.length; j++) {
18888       if (token == tokens2[j]) continue outer;
18889     }
18890     values += (values.length > 0 ? ' ' : '') + token;
18891   }
18892   return values;
18893 }
18894
18895 function removeComments(jqNodes) {
18896   jqNodes = jqLite(jqNodes);
18897   var i = jqNodes.length;
18898
18899   if (i <= 1) {
18900     return jqNodes;
18901   }
18902
18903   while (i--) {
18904     var node = jqNodes[i];
18905     if (node.nodeType === NODE_TYPE_COMMENT) {
18906       splice.call(jqNodes, i, 1);
18907     }
18908   }
18909   return jqNodes;
18910 }
18911
18912 var $controllerMinErr = minErr('$controller');
18913
18914
18915 var CNTRL_REG = /^(\S+)(\s+as\s+([\w$]+))?$/;
18916 function identifierForController(controller, ident) {
18917   if (ident && isString(ident)) return ident;
18918   if (isString(controller)) {
18919     var match = CNTRL_REG.exec(controller);
18920     if (match) return match[3];
18921   }
18922 }
18923
18924
18925 /**
18926  * @ngdoc provider
18927  * @name $controllerProvider
18928  * @description
18929  * The {@link ng.$controller $controller service} is used by Angular to create new
18930  * controllers.
18931  *
18932  * This provider allows controller registration via the
18933  * {@link ng.$controllerProvider#register register} method.
18934  */
18935 function $ControllerProvider() {
18936   var controllers = {},
18937       globals = false;
18938
18939   /**
18940    * @ngdoc method
18941    * @name $controllerProvider#register
18942    * @param {string|Object} name Controller name, or an object map of controllers where the keys are
18943    *    the names and the values are the constructors.
18944    * @param {Function|Array} constructor Controller constructor fn (optionally decorated with DI
18945    *    annotations in the array notation).
18946    */
18947   this.register = function(name, constructor) {
18948     assertNotHasOwnProperty(name, 'controller');
18949     if (isObject(name)) {
18950       extend(controllers, name);
18951     } else {
18952       controllers[name] = constructor;
18953     }
18954   };
18955
18956   /**
18957    * @ngdoc method
18958    * @name $controllerProvider#allowGlobals
18959    * @description If called, allows `$controller` to find controller constructors on `window`
18960    */
18961   this.allowGlobals = function() {
18962     globals = true;
18963   };
18964
18965
18966   this.$get = ['$injector', '$window', function($injector, $window) {
18967
18968     /**
18969      * @ngdoc service
18970      * @name $controller
18971      * @requires $injector
18972      *
18973      * @param {Function|string} constructor If called with a function then it's considered to be the
18974      *    controller constructor function. Otherwise it's considered to be a string which is used
18975      *    to retrieve the controller constructor using the following steps:
18976      *
18977      *    * check if a controller with given name is registered via `$controllerProvider`
18978      *    * check if evaluating the string on the current scope returns a constructor
18979      *    * if $controllerProvider#allowGlobals, check `window[constructor]` on the global
18980      *      `window` object (not recommended)
18981      *
18982      *    The string can use the `controller as property` syntax, where the controller instance is published
18983      *    as the specified property on the `scope`; the `scope` must be injected into `locals` param for this
18984      *    to work correctly.
18985      *
18986      * @param {Object} locals Injection locals for Controller.
18987      * @return {Object} Instance of given controller.
18988      *
18989      * @description
18990      * `$controller` service is responsible for instantiating controllers.
18991      *
18992      * It's just a simple call to {@link auto.$injector $injector}, but extracted into
18993      * a service, so that one can override this service with [BC version](https://gist.github.com/1649788).
18994      */
18995     return function(expression, locals, later, ident) {
18996       // PRIVATE API:
18997       //   param `later` --- indicates that the controller's constructor is invoked at a later time.
18998       //                     If true, $controller will allocate the object with the correct
18999       //                     prototype chain, but will not invoke the controller until a returned
19000       //                     callback is invoked.
19001       //   param `ident` --- An optional label which overrides the label parsed from the controller
19002       //                     expression, if any.
19003       var instance, match, constructor, identifier;
19004       later = later === true;
19005       if (ident && isString(ident)) {
19006         identifier = ident;
19007       }
19008
19009       if (isString(expression)) {
19010         match = expression.match(CNTRL_REG);
19011         if (!match) {
19012           throw $controllerMinErr('ctrlfmt',
19013             "Badly formed controller string '{0}'. " +
19014             "Must match `__name__ as __id__` or `__name__`.", expression);
19015         }
19016         constructor = match[1],
19017         identifier = identifier || match[3];
19018         expression = controllers.hasOwnProperty(constructor)
19019             ? controllers[constructor]
19020             : getter(locals.$scope, constructor, true) ||
19021                 (globals ? getter($window, constructor, true) : undefined);
19022
19023         assertArgFn(expression, constructor, true);
19024       }
19025
19026       if (later) {
19027         // Instantiate controller later:
19028         // This machinery is used to create an instance of the object before calling the
19029         // controller's constructor itself.
19030         //
19031         // This allows properties to be added to the controller before the constructor is
19032         // invoked. Primarily, this is used for isolate scope bindings in $compile.
19033         //
19034         // This feature is not intended for use by applications, and is thus not documented
19035         // publicly.
19036         // Object creation: http://jsperf.com/create-constructor/2
19037         var controllerPrototype = (isArray(expression) ?
19038           expression[expression.length - 1] : expression).prototype;
19039         instance = Object.create(controllerPrototype || null);
19040
19041         if (identifier) {
19042           addIdentifier(locals, identifier, instance, constructor || expression.name);
19043         }
19044
19045         var instantiate;
19046         return instantiate = extend(function() {
19047           var result = $injector.invoke(expression, instance, locals, constructor);
19048           if (result !== instance && (isObject(result) || isFunction(result))) {
19049             instance = result;
19050             if (identifier) {
19051               // If result changed, re-assign controllerAs value to scope.
19052               addIdentifier(locals, identifier, instance, constructor || expression.name);
19053             }
19054           }
19055           return instance;
19056         }, {
19057           instance: instance,
19058           identifier: identifier
19059         });
19060       }
19061
19062       instance = $injector.instantiate(expression, locals, constructor);
19063
19064       if (identifier) {
19065         addIdentifier(locals, identifier, instance, constructor || expression.name);
19066       }
19067
19068       return instance;
19069     };
19070
19071     function addIdentifier(locals, identifier, instance, name) {
19072       if (!(locals && isObject(locals.$scope))) {
19073         throw minErr('$controller')('noscp',
19074           "Cannot export controller '{0}' as '{1}'! No $scope object provided via `locals`.",
19075           name, identifier);
19076       }
19077
19078       locals.$scope[identifier] = instance;
19079     }
19080   }];
19081 }
19082
19083 /**
19084  * @ngdoc service
19085  * @name $document
19086  * @requires $window
19087  *
19088  * @description
19089  * A {@link angular.element jQuery or jqLite} wrapper for the browser's `window.document` object.
19090  *
19091  * @example
19092    <example module="documentExample">
19093      <file name="index.html">
19094        <div ng-controller="ExampleController">
19095          <p>$document title: <b ng-bind="title"></b></p>
19096          <p>window.document title: <b ng-bind="windowTitle"></b></p>
19097        </div>
19098      </file>
19099      <file name="script.js">
19100        angular.module('documentExample', [])
19101          .controller('ExampleController', ['$scope', '$document', function($scope, $document) {
19102            $scope.title = $document[0].title;
19103            $scope.windowTitle = angular.element(window.document)[0].title;
19104          }]);
19105      </file>
19106    </example>
19107  */
19108 function $DocumentProvider() {
19109   this.$get = ['$window', function(window) {
19110     return jqLite(window.document);
19111   }];
19112 }
19113
19114 /**
19115  * @ngdoc service
19116  * @name $exceptionHandler
19117  * @requires ng.$log
19118  *
19119  * @description
19120  * Any uncaught exception in angular expressions is delegated to this service.
19121  * The default implementation simply delegates to `$log.error` which logs it into
19122  * the browser console.
19123  *
19124  * In unit tests, if `angular-mocks.js` is loaded, this service is overridden by
19125  * {@link ngMock.$exceptionHandler mock $exceptionHandler} which aids in testing.
19126  *
19127  * ## Example:
19128  *
19129  * ```js
19130  *   angular.module('exceptionOverride', []).factory('$exceptionHandler', function() {
19131  *     return function(exception, cause) {
19132  *       exception.message += ' (caused by "' + cause + '")';
19133  *       throw exception;
19134  *     };
19135  *   });
19136  * ```
19137  *
19138  * This example will override the normal action of `$exceptionHandler`, to make angular
19139  * exceptions fail hard when they happen, instead of just logging to the console.
19140  *
19141  * <hr />
19142  * Note, that code executed in event-listeners (even those registered using jqLite's `on`/`bind`
19143  * methods) does not delegate exceptions to the {@link ng.$exceptionHandler $exceptionHandler}
19144  * (unless executed during a digest).
19145  *
19146  * If you wish, you can manually delegate exceptions, e.g.
19147  * `try { ... } catch(e) { $exceptionHandler(e); }`
19148  *
19149  * @param {Error} exception Exception associated with the error.
19150  * @param {string=} cause optional information about the context in which
19151  *       the error was thrown.
19152  *
19153  */
19154 function $ExceptionHandlerProvider() {
19155   this.$get = ['$log', function($log) {
19156     return function(exception, cause) {
19157       $log.error.apply($log, arguments);
19158     };
19159   }];
19160 }
19161
19162 var $$ForceReflowProvider = function() {
19163   this.$get = ['$document', function($document) {
19164     return function(domNode) {
19165       //the line below will force the browser to perform a repaint so
19166       //that all the animated elements within the animation frame will
19167       //be properly updated and drawn on screen. This is required to
19168       //ensure that the preparation animation is properly flushed so that
19169       //the active state picks up from there. DO NOT REMOVE THIS LINE.
19170       //DO NOT OPTIMIZE THIS LINE. THE MINIFIER WILL REMOVE IT OTHERWISE WHICH
19171       //WILL RESULT IN AN UNPREDICTABLE BUG THAT IS VERY HARD TO TRACK DOWN AND
19172       //WILL TAKE YEARS AWAY FROM YOUR LIFE.
19173       if (domNode) {
19174         if (!domNode.nodeType && domNode instanceof jqLite) {
19175           domNode = domNode[0];
19176         }
19177       } else {
19178         domNode = $document[0].body;
19179       }
19180       return domNode.offsetWidth + 1;
19181     };
19182   }];
19183 };
19184
19185 var APPLICATION_JSON = 'application/json';
19186 var CONTENT_TYPE_APPLICATION_JSON = {'Content-Type': APPLICATION_JSON + ';charset=utf-8'};
19187 var JSON_START = /^\[|^\{(?!\{)/;
19188 var JSON_ENDS = {
19189   '[': /]$/,
19190   '{': /}$/
19191 };
19192 var JSON_PROTECTION_PREFIX = /^\)\]\}',?\n/;
19193 var $httpMinErr = minErr('$http');
19194 var $httpMinErrLegacyFn = function(method) {
19195   return function() {
19196     throw $httpMinErr('legacy', 'The method `{0}` on the promise returned from `$http` has been disabled.', method);
19197   };
19198 };
19199
19200 function serializeValue(v) {
19201   if (isObject(v)) {
19202     return isDate(v) ? v.toISOString() : toJson(v);
19203   }
19204   return v;
19205 }
19206
19207
19208 function $HttpParamSerializerProvider() {
19209   /**
19210    * @ngdoc service
19211    * @name $httpParamSerializer
19212    * @description
19213    *
19214    * Default {@link $http `$http`} params serializer that converts objects to strings
19215    * according to the following rules:
19216    *
19217    * * `{'foo': 'bar'}` results in `foo=bar`
19218    * * `{'foo': Date.now()}` results in `foo=2015-04-01T09%3A50%3A49.262Z` (`toISOString()` and encoded representation of a Date object)
19219    * * `{'foo': ['bar', 'baz']}` results in `foo=bar&foo=baz` (repeated key for each array element)
19220    * * `{'foo': {'bar':'baz'}}` results in `foo=%7B%22bar%22%3A%22baz%22%7D"` (stringified and encoded representation of an object)
19221    *
19222    * Note that serializer will sort the request parameters alphabetically.
19223    * */
19224
19225   this.$get = function() {
19226     return function ngParamSerializer(params) {
19227       if (!params) return '';
19228       var parts = [];
19229       forEachSorted(params, function(value, key) {
19230         if (value === null || isUndefined(value)) return;
19231         if (isArray(value)) {
19232           forEach(value, function(v, k) {
19233             parts.push(encodeUriQuery(key)  + '=' + encodeUriQuery(serializeValue(v)));
19234           });
19235         } else {
19236           parts.push(encodeUriQuery(key) + '=' + encodeUriQuery(serializeValue(value)));
19237         }
19238       });
19239
19240       return parts.join('&');
19241     };
19242   };
19243 }
19244
19245 function $HttpParamSerializerJQLikeProvider() {
19246   /**
19247    * @ngdoc service
19248    * @name $httpParamSerializerJQLike
19249    * @description
19250    *
19251    * Alternative {@link $http `$http`} params serializer that follows
19252    * jQuery's [`param()`](http://api.jquery.com/jquery.param/) method logic.
19253    * The serializer will also sort the params alphabetically.
19254    *
19255    * To use it for serializing `$http` request parameters, set it as the `paramSerializer` property:
19256    *
19257    * ```js
19258    * $http({
19259    *   url: myUrl,
19260    *   method: 'GET',
19261    *   params: myParams,
19262    *   paramSerializer: '$httpParamSerializerJQLike'
19263    * });
19264    * ```
19265    *
19266    * It is also possible to set it as the default `paramSerializer` in the
19267    * {@link $httpProvider#defaults `$httpProvider`}.
19268    *
19269    * Additionally, you can inject the serializer and use it explicitly, for example to serialize
19270    * form data for submission:
19271    *
19272    * ```js
19273    * .controller(function($http, $httpParamSerializerJQLike) {
19274    *   //...
19275    *
19276    *   $http({
19277    *     url: myUrl,
19278    *     method: 'POST',
19279    *     data: $httpParamSerializerJQLike(myData),
19280    *     headers: {
19281    *       'Content-Type': 'application/x-www-form-urlencoded'
19282    *     }
19283    *   });
19284    *
19285    * });
19286    * ```
19287    *
19288    * */
19289   this.$get = function() {
19290     return function jQueryLikeParamSerializer(params) {
19291       if (!params) return '';
19292       var parts = [];
19293       serialize(params, '', true);
19294       return parts.join('&');
19295
19296       function serialize(toSerialize, prefix, topLevel) {
19297         if (toSerialize === null || isUndefined(toSerialize)) return;
19298         if (isArray(toSerialize)) {
19299           forEach(toSerialize, function(value, index) {
19300             serialize(value, prefix + '[' + (isObject(value) ? index : '') + ']');
19301           });
19302         } else if (isObject(toSerialize) && !isDate(toSerialize)) {
19303           forEachSorted(toSerialize, function(value, key) {
19304             serialize(value, prefix +
19305                 (topLevel ? '' : '[') +
19306                 key +
19307                 (topLevel ? '' : ']'));
19308           });
19309         } else {
19310           parts.push(encodeUriQuery(prefix) + '=' + encodeUriQuery(serializeValue(toSerialize)));
19311         }
19312       }
19313     };
19314   };
19315 }
19316
19317 function defaultHttpResponseTransform(data, headers) {
19318   if (isString(data)) {
19319     // Strip json vulnerability protection prefix and trim whitespace
19320     var tempData = data.replace(JSON_PROTECTION_PREFIX, '').trim();
19321
19322     if (tempData) {
19323       var contentType = headers('Content-Type');
19324       if ((contentType && (contentType.indexOf(APPLICATION_JSON) === 0)) || isJsonLike(tempData)) {
19325         data = fromJson(tempData);
19326       }
19327     }
19328   }
19329
19330   return data;
19331 }
19332
19333 function isJsonLike(str) {
19334     var jsonStart = str.match(JSON_START);
19335     return jsonStart && JSON_ENDS[jsonStart[0]].test(str);
19336 }
19337
19338 /**
19339  * Parse headers into key value object
19340  *
19341  * @param {string} headers Raw headers as a string
19342  * @returns {Object} Parsed headers as key value object
19343  */
19344 function parseHeaders(headers) {
19345   var parsed = createMap(), i;
19346
19347   function fillInParsed(key, val) {
19348     if (key) {
19349       parsed[key] = parsed[key] ? parsed[key] + ', ' + val : val;
19350     }
19351   }
19352
19353   if (isString(headers)) {
19354     forEach(headers.split('\n'), function(line) {
19355       i = line.indexOf(':');
19356       fillInParsed(lowercase(trim(line.substr(0, i))), trim(line.substr(i + 1)));
19357     });
19358   } else if (isObject(headers)) {
19359     forEach(headers, function(headerVal, headerKey) {
19360       fillInParsed(lowercase(headerKey), trim(headerVal));
19361     });
19362   }
19363
19364   return parsed;
19365 }
19366
19367
19368 /**
19369  * Returns a function that provides access to parsed headers.
19370  *
19371  * Headers are lazy parsed when first requested.
19372  * @see parseHeaders
19373  *
19374  * @param {(string|Object)} headers Headers to provide access to.
19375  * @returns {function(string=)} Returns a getter function which if called with:
19376  *
19377  *   - if called with single an argument returns a single header value or null
19378  *   - if called with no arguments returns an object containing all headers.
19379  */
19380 function headersGetter(headers) {
19381   var headersObj;
19382
19383   return function(name) {
19384     if (!headersObj) headersObj =  parseHeaders(headers);
19385
19386     if (name) {
19387       var value = headersObj[lowercase(name)];
19388       if (value === void 0) {
19389         value = null;
19390       }
19391       return value;
19392     }
19393
19394     return headersObj;
19395   };
19396 }
19397
19398
19399 /**
19400  * Chain all given functions
19401  *
19402  * This function is used for both request and response transforming
19403  *
19404  * @param {*} data Data to transform.
19405  * @param {function(string=)} headers HTTP headers getter fn.
19406  * @param {number} status HTTP status code of the response.
19407  * @param {(Function|Array.<Function>)} fns Function or an array of functions.
19408  * @returns {*} Transformed data.
19409  */
19410 function transformData(data, headers, status, fns) {
19411   if (isFunction(fns)) {
19412     return fns(data, headers, status);
19413   }
19414
19415   forEach(fns, function(fn) {
19416     data = fn(data, headers, status);
19417   });
19418
19419   return data;
19420 }
19421
19422
19423 function isSuccess(status) {
19424   return 200 <= status && status < 300;
19425 }
19426
19427
19428 /**
19429  * @ngdoc provider
19430  * @name $httpProvider
19431  * @description
19432  * Use `$httpProvider` to change the default behavior of the {@link ng.$http $http} service.
19433  * */
19434 function $HttpProvider() {
19435   /**
19436    * @ngdoc property
19437    * @name $httpProvider#defaults
19438    * @description
19439    *
19440    * Object containing default values for all {@link ng.$http $http} requests.
19441    *
19442    * - **`defaults.cache`** - {Object} - an object built with {@link ng.$cacheFactory `$cacheFactory`}
19443    * that will provide the cache for all requests who set their `cache` property to `true`.
19444    * If you set the `defaults.cache = false` then only requests that specify their own custom
19445    * cache object will be cached. See {@link $http#caching $http Caching} for more information.
19446    *
19447    * - **`defaults.xsrfCookieName`** - {string} - Name of cookie containing the XSRF token.
19448    * Defaults value is `'XSRF-TOKEN'`.
19449    *
19450    * - **`defaults.xsrfHeaderName`** - {string} - Name of HTTP header to populate with the
19451    * XSRF token. Defaults value is `'X-XSRF-TOKEN'`.
19452    *
19453    * - **`defaults.headers`** - {Object} - Default headers for all $http requests.
19454    * Refer to {@link ng.$http#setting-http-headers $http} for documentation on
19455    * setting default headers.
19456    *     - **`defaults.headers.common`**
19457    *     - **`defaults.headers.post`**
19458    *     - **`defaults.headers.put`**
19459    *     - **`defaults.headers.patch`**
19460    *
19461    *
19462    * - **`defaults.paramSerializer`** - `{string|function(Object<string,string>):string}` - A function
19463    *  used to the prepare string representation of request parameters (specified as an object).
19464    *  If specified as string, it is interpreted as a function registered with the {@link auto.$injector $injector}.
19465    *  Defaults to {@link ng.$httpParamSerializer $httpParamSerializer}.
19466    *
19467    **/
19468   var defaults = this.defaults = {
19469     // transform incoming response data
19470     transformResponse: [defaultHttpResponseTransform],
19471
19472     // transform outgoing request data
19473     transformRequest: [function(d) {
19474       return isObject(d) && !isFile(d) && !isBlob(d) && !isFormData(d) ? toJson(d) : d;
19475     }],
19476
19477     // default headers
19478     headers: {
19479       common: {
19480         'Accept': 'application/json, text/plain, */*'
19481       },
19482       post:   shallowCopy(CONTENT_TYPE_APPLICATION_JSON),
19483       put:    shallowCopy(CONTENT_TYPE_APPLICATION_JSON),
19484       patch:  shallowCopy(CONTENT_TYPE_APPLICATION_JSON)
19485     },
19486
19487     xsrfCookieName: 'XSRF-TOKEN',
19488     xsrfHeaderName: 'X-XSRF-TOKEN',
19489
19490     paramSerializer: '$httpParamSerializer'
19491   };
19492
19493   var useApplyAsync = false;
19494   /**
19495    * @ngdoc method
19496    * @name $httpProvider#useApplyAsync
19497    * @description
19498    *
19499    * Configure $http service to combine processing of multiple http responses received at around
19500    * the same time via {@link ng.$rootScope.Scope#$applyAsync $rootScope.$applyAsync}. This can result in
19501    * significant performance improvement for bigger applications that make many HTTP requests
19502    * concurrently (common during application bootstrap).
19503    *
19504    * Defaults to false. If no value is specified, returns the current configured value.
19505    *
19506    * @param {boolean=} value If true, when requests are loaded, they will schedule a deferred
19507    *    "apply" on the next tick, giving time for subsequent requests in a roughly ~10ms window
19508    *    to load and share the same digest cycle.
19509    *
19510    * @returns {boolean|Object} If a value is specified, returns the $httpProvider for chaining.
19511    *    otherwise, returns the current configured value.
19512    **/
19513   this.useApplyAsync = function(value) {
19514     if (isDefined(value)) {
19515       useApplyAsync = !!value;
19516       return this;
19517     }
19518     return useApplyAsync;
19519   };
19520
19521   var useLegacyPromise = true;
19522   /**
19523    * @ngdoc method
19524    * @name $httpProvider#useLegacyPromiseExtensions
19525    * @description
19526    *
19527    * Configure `$http` service to return promises without the shorthand methods `success` and `error`.
19528    * This should be used to make sure that applications work without these methods.
19529    *
19530    * Defaults to true. If no value is specified, returns the current configured value.
19531    *
19532    * @param {boolean=} value If true, `$http` will return a promise with the deprecated legacy `success` and `error` methods.
19533    *
19534    * @returns {boolean|Object} If a value is specified, returns the $httpProvider for chaining.
19535    *    otherwise, returns the current configured value.
19536    **/
19537   this.useLegacyPromiseExtensions = function(value) {
19538     if (isDefined(value)) {
19539       useLegacyPromise = !!value;
19540       return this;
19541     }
19542     return useLegacyPromise;
19543   };
19544
19545   /**
19546    * @ngdoc property
19547    * @name $httpProvider#interceptors
19548    * @description
19549    *
19550    * Array containing service factories for all synchronous or asynchronous {@link ng.$http $http}
19551    * pre-processing of request or postprocessing of responses.
19552    *
19553    * These service factories are ordered by request, i.e. they are applied in the same order as the
19554    * array, on request, but reverse order, on response.
19555    *
19556    * {@link ng.$http#interceptors Interceptors detailed info}
19557    **/
19558   var interceptorFactories = this.interceptors = [];
19559
19560   this.$get = ['$httpBackend', '$$cookieReader', '$cacheFactory', '$rootScope', '$q', '$injector',
19561       function($httpBackend, $$cookieReader, $cacheFactory, $rootScope, $q, $injector) {
19562
19563     var defaultCache = $cacheFactory('$http');
19564
19565     /**
19566      * Make sure that default param serializer is exposed as a function
19567      */
19568     defaults.paramSerializer = isString(defaults.paramSerializer) ?
19569       $injector.get(defaults.paramSerializer) : defaults.paramSerializer;
19570
19571     /**
19572      * Interceptors stored in reverse order. Inner interceptors before outer interceptors.
19573      * The reversal is needed so that we can build up the interception chain around the
19574      * server request.
19575      */
19576     var reversedInterceptors = [];
19577
19578     forEach(interceptorFactories, function(interceptorFactory) {
19579       reversedInterceptors.unshift(isString(interceptorFactory)
19580           ? $injector.get(interceptorFactory) : $injector.invoke(interceptorFactory));
19581     });
19582
19583     /**
19584      * @ngdoc service
19585      * @kind function
19586      * @name $http
19587      * @requires ng.$httpBackend
19588      * @requires $cacheFactory
19589      * @requires $rootScope
19590      * @requires $q
19591      * @requires $injector
19592      *
19593      * @description
19594      * The `$http` service is a core Angular service that facilitates communication with the remote
19595      * HTTP servers via the browser's [XMLHttpRequest](https://developer.mozilla.org/en/xmlhttprequest)
19596      * object or via [JSONP](http://en.wikipedia.org/wiki/JSONP).
19597      *
19598      * For unit testing applications that use `$http` service, see
19599      * {@link ngMock.$httpBackend $httpBackend mock}.
19600      *
19601      * For a higher level of abstraction, please check out the {@link ngResource.$resource
19602      * $resource} service.
19603      *
19604      * The $http API is based on the {@link ng.$q deferred/promise APIs} exposed by
19605      * the $q service. While for simple usage patterns this doesn't matter much, for advanced usage
19606      * it is important to familiarize yourself with these APIs and the guarantees they provide.
19607      *
19608      *
19609      * ## General usage
19610      * The `$http` service is a function which takes a single argument — a {@link $http#usage configuration object} —
19611      * that is used to generate an HTTP request and returns  a {@link ng.$q promise}.
19612      *
19613      * ```js
19614      *   // Simple GET request example:
19615      *   $http({
19616      *     method: 'GET',
19617      *     url: '/someUrl'
19618      *   }).then(function successCallback(response) {
19619      *       // this callback will be called asynchronously
19620      *       // when the response is available
19621      *     }, function errorCallback(response) {
19622      *       // called asynchronously if an error occurs
19623      *       // or server returns response with an error status.
19624      *     });
19625      * ```
19626      *
19627      * The response object has these properties:
19628      *
19629      *   - **data** – `{string|Object}` – The response body transformed with the transform
19630      *     functions.
19631      *   - **status** – `{number}` – HTTP status code of the response.
19632      *   - **headers** – `{function([headerName])}` – Header getter function.
19633      *   - **config** – `{Object}` – The configuration object that was used to generate the request.
19634      *   - **statusText** – `{string}` – HTTP status text of the response.
19635      *
19636      * A response status code between 200 and 299 is considered a success status and
19637      * will result in the success callback being called. Note that if the response is a redirect,
19638      * XMLHttpRequest will transparently follow it, meaning that the error callback will not be
19639      * called for such responses.
19640      *
19641      *
19642      * ## Shortcut methods
19643      *
19644      * Shortcut methods are also available. All shortcut methods require passing in the URL, and
19645      * request data must be passed in for POST/PUT requests. An optional config can be passed as the
19646      * last argument.
19647      *
19648      * ```js
19649      *   $http.get('/someUrl', config).then(successCallback, errorCallback);
19650      *   $http.post('/someUrl', data, config).then(successCallback, errorCallback);
19651      * ```
19652      *
19653      * Complete list of shortcut methods:
19654      *
19655      * - {@link ng.$http#get $http.get}
19656      * - {@link ng.$http#head $http.head}
19657      * - {@link ng.$http#post $http.post}
19658      * - {@link ng.$http#put $http.put}
19659      * - {@link ng.$http#delete $http.delete}
19660      * - {@link ng.$http#jsonp $http.jsonp}
19661      * - {@link ng.$http#patch $http.patch}
19662      *
19663      *
19664      * ## Writing Unit Tests that use $http
19665      * When unit testing (using {@link ngMock ngMock}), it is necessary to call
19666      * {@link ngMock.$httpBackend#flush $httpBackend.flush()} to flush each pending
19667      * request using trained responses.
19668      *
19669      * ```
19670      * $httpBackend.expectGET(...);
19671      * $http.get(...);
19672      * $httpBackend.flush();
19673      * ```
19674      *
19675      * ## Deprecation Notice
19676      * <div class="alert alert-danger">
19677      *   The `$http` legacy promise methods `success` and `error` have been deprecated.
19678      *   Use the standard `then` method instead.
19679      *   If {@link $httpProvider#useLegacyPromiseExtensions `$httpProvider.useLegacyPromiseExtensions`} is set to
19680      *   `false` then these methods will throw {@link $http:legacy `$http/legacy`} error.
19681      * </div>
19682      *
19683      * ## Setting HTTP Headers
19684      *
19685      * The $http service will automatically add certain HTTP headers to all requests. These defaults
19686      * can be fully configured by accessing the `$httpProvider.defaults.headers` configuration
19687      * object, which currently contains this default configuration:
19688      *
19689      * - `$httpProvider.defaults.headers.common` (headers that are common for all requests):
19690      *   - `Accept: application/json, text/plain, * / *`
19691      * - `$httpProvider.defaults.headers.post`: (header defaults for POST requests)
19692      *   - `Content-Type: application/json`
19693      * - `$httpProvider.defaults.headers.put` (header defaults for PUT requests)
19694      *   - `Content-Type: application/json`
19695      *
19696      * To add or overwrite these defaults, simply add or remove a property from these configuration
19697      * objects. To add headers for an HTTP method other than POST or PUT, simply add a new object
19698      * with the lowercased HTTP method name as the key, e.g.
19699      * `$httpProvider.defaults.headers.get = { 'My-Header' : 'value' }`.
19700      *
19701      * The defaults can also be set at runtime via the `$http.defaults` object in the same
19702      * fashion. For example:
19703      *
19704      * ```
19705      * module.run(function($http) {
19706      *   $http.defaults.headers.common.Authorization = 'Basic YmVlcDpib29w';
19707      * });
19708      * ```
19709      *
19710      * In addition, you can supply a `headers` property in the config object passed when
19711      * calling `$http(config)`, which overrides the defaults without changing them globally.
19712      *
19713      * To explicitly remove a header automatically added via $httpProvider.defaults.headers on a per request basis,
19714      * Use the `headers` property, setting the desired header to `undefined`. For example:
19715      *
19716      * ```js
19717      * var req = {
19718      *  method: 'POST',
19719      *  url: 'http://example.com',
19720      *  headers: {
19721      *    'Content-Type': undefined
19722      *  },
19723      *  data: { test: 'test' }
19724      * }
19725      *
19726      * $http(req).then(function(){...}, function(){...});
19727      * ```
19728      *
19729      * ## Transforming Requests and Responses
19730      *
19731      * Both requests and responses can be transformed using transformation functions: `transformRequest`
19732      * and `transformResponse`. These properties can be a single function that returns
19733      * the transformed value (`function(data, headersGetter, status)`) or an array of such transformation functions,
19734      * which allows you to `push` or `unshift` a new transformation function into the transformation chain.
19735      *
19736      * ### Default Transformations
19737      *
19738      * The `$httpProvider` provider and `$http` service expose `defaults.transformRequest` and
19739      * `defaults.transformResponse` properties. If a request does not provide its own transformations
19740      * then these will be applied.
19741      *
19742      * You can augment or replace the default transformations by modifying these properties by adding to or
19743      * replacing the array.
19744      *
19745      * Angular provides the following default transformations:
19746      *
19747      * Request transformations (`$httpProvider.defaults.transformRequest` and `$http.defaults.transformRequest`):
19748      *
19749      * - If the `data` property of the request configuration object contains an object, serialize it
19750      *   into JSON format.
19751      *
19752      * Response transformations (`$httpProvider.defaults.transformResponse` and `$http.defaults.transformResponse`):
19753      *
19754      *  - If XSRF prefix is detected, strip it (see Security Considerations section below).
19755      *  - If JSON response is detected, deserialize it using a JSON parser.
19756      *
19757      *
19758      * ### Overriding the Default Transformations Per Request
19759      *
19760      * If you wish override the request/response transformations only for a single request then provide
19761      * `transformRequest` and/or `transformResponse` properties on the configuration object passed
19762      * into `$http`.
19763      *
19764      * Note that if you provide these properties on the config object the default transformations will be
19765      * overwritten. If you wish to augment the default transformations then you must include them in your
19766      * local transformation array.
19767      *
19768      * The following code demonstrates adding a new response transformation to be run after the default response
19769      * transformations have been run.
19770      *
19771      * ```js
19772      * function appendTransform(defaults, transform) {
19773      *
19774      *   // We can't guarantee that the default transformation is an array
19775      *   defaults = angular.isArray(defaults) ? defaults : [defaults];
19776      *
19777      *   // Append the new transformation to the defaults
19778      *   return defaults.concat(transform);
19779      * }
19780      *
19781      * $http({
19782      *   url: '...',
19783      *   method: 'GET',
19784      *   transformResponse: appendTransform($http.defaults.transformResponse, function(value) {
19785      *     return doTransform(value);
19786      *   })
19787      * });
19788      * ```
19789      *
19790      *
19791      * ## Caching
19792      *
19793      * To enable caching, set the request configuration `cache` property to `true` (to use default
19794      * cache) or to a custom cache object (built with {@link ng.$cacheFactory `$cacheFactory`}).
19795      * When the cache is enabled, `$http` stores the response from the server in the specified
19796      * cache. The next time the same request is made, the response is served from the cache without
19797      * sending a request to the server.
19798      *
19799      * Note that even if the response is served from cache, delivery of the data is asynchronous in
19800      * the same way that real requests are.
19801      *
19802      * If there are multiple GET requests for the same URL that should be cached using the same
19803      * cache, but the cache is not populated yet, only one request to the server will be made and
19804      * the remaining requests will be fulfilled using the response from the first request.
19805      *
19806      * You can change the default cache to a new object (built with
19807      * {@link ng.$cacheFactory `$cacheFactory`}) by updating the
19808      * {@link ng.$http#defaults `$http.defaults.cache`} property. All requests who set
19809      * their `cache` property to `true` will now use this cache object.
19810      *
19811      * If you set the default cache to `false` then only requests that specify their own custom
19812      * cache object will be cached.
19813      *
19814      * ## Interceptors
19815      *
19816      * Before you start creating interceptors, be sure to understand the
19817      * {@link ng.$q $q and deferred/promise APIs}.
19818      *
19819      * For purposes of global error handling, authentication, or any kind of synchronous or
19820      * asynchronous pre-processing of request or postprocessing of responses, it is desirable to be
19821      * able to intercept requests before they are handed to the server and
19822      * responses before they are handed over to the application code that
19823      * initiated these requests. The interceptors leverage the {@link ng.$q
19824      * promise APIs} to fulfill this need for both synchronous and asynchronous pre-processing.
19825      *
19826      * The interceptors are service factories that are registered with the `$httpProvider` by
19827      * adding them to the `$httpProvider.interceptors` array. The factory is called and
19828      * injected with dependencies (if specified) and returns the interceptor.
19829      *
19830      * There are two kinds of interceptors (and two kinds of rejection interceptors):
19831      *
19832      *   * `request`: interceptors get called with a http {@link $http#usage config} object. The function is free to
19833      *     modify the `config` object or create a new one. The function needs to return the `config`
19834      *     object directly, or a promise containing the `config` or a new `config` object.
19835      *   * `requestError`: interceptor gets called when a previous interceptor threw an error or
19836      *     resolved with a rejection.
19837      *   * `response`: interceptors get called with http `response` object. The function is free to
19838      *     modify the `response` object or create a new one. The function needs to return the `response`
19839      *     object directly, or as a promise containing the `response` or a new `response` object.
19840      *   * `responseError`: interceptor gets called when a previous interceptor threw an error or
19841      *     resolved with a rejection.
19842      *
19843      *
19844      * ```js
19845      *   // register the interceptor as a service
19846      *   $provide.factory('myHttpInterceptor', function($q, dependency1, dependency2) {
19847      *     return {
19848      *       // optional method
19849      *       'request': function(config) {
19850      *         // do something on success
19851      *         return config;
19852      *       },
19853      *
19854      *       // optional method
19855      *      'requestError': function(rejection) {
19856      *         // do something on error
19857      *         if (canRecover(rejection)) {
19858      *           return responseOrNewPromise
19859      *         }
19860      *         return $q.reject(rejection);
19861      *       },
19862      *
19863      *
19864      *
19865      *       // optional method
19866      *       'response': function(response) {
19867      *         // do something on success
19868      *         return response;
19869      *       },
19870      *
19871      *       // optional method
19872      *      'responseError': function(rejection) {
19873      *         // do something on error
19874      *         if (canRecover(rejection)) {
19875      *           return responseOrNewPromise
19876      *         }
19877      *         return $q.reject(rejection);
19878      *       }
19879      *     };
19880      *   });
19881      *
19882      *   $httpProvider.interceptors.push('myHttpInterceptor');
19883      *
19884      *
19885      *   // alternatively, register the interceptor via an anonymous factory
19886      *   $httpProvider.interceptors.push(function($q, dependency1, dependency2) {
19887      *     return {
19888      *      'request': function(config) {
19889      *          // same as above
19890      *       },
19891      *
19892      *       'response': function(response) {
19893      *          // same as above
19894      *       }
19895      *     };
19896      *   });
19897      * ```
19898      *
19899      * ## Security Considerations
19900      *
19901      * When designing web applications, consider security threats from:
19902      *
19903      * - [JSON vulnerability](http://haacked.com/archive/2008/11/20/anatomy-of-a-subtle-json-vulnerability.aspx)
19904      * - [XSRF](http://en.wikipedia.org/wiki/Cross-site_request_forgery)
19905      *
19906      * Both server and the client must cooperate in order to eliminate these threats. Angular comes
19907      * pre-configured with strategies that address these issues, but for this to work backend server
19908      * cooperation is required.
19909      *
19910      * ### JSON Vulnerability Protection
19911      *
19912      * A [JSON vulnerability](http://haacked.com/archive/2008/11/20/anatomy-of-a-subtle-json-vulnerability.aspx)
19913      * allows third party website to turn your JSON resource URL into
19914      * [JSONP](http://en.wikipedia.org/wiki/JSONP) request under some conditions. To
19915      * counter this your server can prefix all JSON requests with following string `")]}',\n"`.
19916      * Angular will automatically strip the prefix before processing it as JSON.
19917      *
19918      * For example if your server needs to return:
19919      * ```js
19920      * ['one','two']
19921      * ```
19922      *
19923      * which is vulnerable to attack, your server can return:
19924      * ```js
19925      * )]}',
19926      * ['one','two']
19927      * ```
19928      *
19929      * Angular will strip the prefix, before processing the JSON.
19930      *
19931      *
19932      * ### Cross Site Request Forgery (XSRF) Protection
19933      *
19934      * [XSRF](http://en.wikipedia.org/wiki/Cross-site_request_forgery) is an attack technique by
19935      * which the attacker can trick an authenticated user into unknowingly executing actions on your
19936      * website. Angular provides a mechanism to counter XSRF. When performing XHR requests, the
19937      * $http service reads a token from a cookie (by default, `XSRF-TOKEN`) and sets it as an HTTP
19938      * header (`X-XSRF-TOKEN`). Since only JavaScript that runs on your domain could read the
19939      * cookie, your server can be assured that the XHR came from JavaScript running on your domain.
19940      * The header will not be set for cross-domain requests.
19941      *
19942      * To take advantage of this, your server needs to set a token in a JavaScript readable session
19943      * cookie called `XSRF-TOKEN` on the first HTTP GET request. On subsequent XHR requests the
19944      * server can verify that the cookie matches `X-XSRF-TOKEN` HTTP header, and therefore be sure
19945      * that only JavaScript running on your domain could have sent the request. The token must be
19946      * unique for each user and must be verifiable by the server (to prevent the JavaScript from
19947      * making up its own tokens). We recommend that the token is a digest of your site's
19948      * authentication cookie with a [salt](https://en.wikipedia.org/wiki/Salt_(cryptography&#41;)
19949      * for added security.
19950      *
19951      * The name of the headers can be specified using the xsrfHeaderName and xsrfCookieName
19952      * properties of either $httpProvider.defaults at config-time, $http.defaults at run-time,
19953      * or the per-request config object.
19954      *
19955      * In order to prevent collisions in environments where multiple Angular apps share the
19956      * same domain or subdomain, we recommend that each application uses unique cookie name.
19957      *
19958      * @param {object} config Object describing the request to be made and how it should be
19959      *    processed. The object has following properties:
19960      *
19961      *    - **method** – `{string}` – HTTP method (e.g. 'GET', 'POST', etc)
19962      *    - **url** – `{string}` – Absolute or relative URL of the resource that is being requested.
19963      *    - **params** – `{Object.<string|Object>}` – Map of strings or objects which will be serialized
19964      *      with the `paramSerializer` and appended as GET parameters.
19965      *    - **data** – `{string|Object}` – Data to be sent as the request message data.
19966      *    - **headers** – `{Object}` – Map of strings or functions which return strings representing
19967      *      HTTP headers to send to the server. If the return value of a function is null, the
19968      *      header will not be sent. Functions accept a config object as an argument.
19969      *    - **xsrfHeaderName** – `{string}` – Name of HTTP header to populate with the XSRF token.
19970      *    - **xsrfCookieName** – `{string}` – Name of cookie containing the XSRF token.
19971      *    - **transformRequest** –
19972      *      `{function(data, headersGetter)|Array.<function(data, headersGetter)>}` –
19973      *      transform function or an array of such functions. The transform function takes the http
19974      *      request body and headers and returns its transformed (typically serialized) version.
19975      *      See {@link ng.$http#overriding-the-default-transformations-per-request
19976      *      Overriding the Default Transformations}
19977      *    - **transformResponse** –
19978      *      `{function(data, headersGetter, status)|Array.<function(data, headersGetter, status)>}` –
19979      *      transform function or an array of such functions. The transform function takes the http
19980      *      response body, headers and status and returns its transformed (typically deserialized) version.
19981      *      See {@link ng.$http#overriding-the-default-transformations-per-request
19982      *      Overriding the Default TransformationjqLiks}
19983      *    - **paramSerializer** - `{string|function(Object<string,string>):string}` - A function used to
19984      *      prepare the string representation of request parameters (specified as an object).
19985      *      If specified as string, it is interpreted as function registered with the
19986      *      {@link $injector $injector}, which means you can create your own serializer
19987      *      by registering it as a {@link auto.$provide#service service}.
19988      *      The default serializer is the {@link $httpParamSerializer $httpParamSerializer};
19989      *      alternatively, you can use the {@link $httpParamSerializerJQLike $httpParamSerializerJQLike}
19990      *    - **cache** – `{boolean|Cache}` – If true, a default $http cache will be used to cache the
19991      *      GET request, otherwise if a cache instance built with
19992      *      {@link ng.$cacheFactory $cacheFactory}, this cache will be used for
19993      *      caching.
19994      *    - **timeout** – `{number|Promise}` – timeout in milliseconds, or {@link ng.$q promise}
19995      *      that should abort the request when resolved.
19996      *    - **withCredentials** - `{boolean}` - whether to set the `withCredentials` flag on the
19997      *      XHR object. See [requests with credentials](https://developer.mozilla.org/docs/Web/HTTP/Access_control_CORS#Requests_with_credentials)
19998      *      for more information.
19999      *    - **responseType** - `{string}` - see
20000      *      [XMLHttpRequest.responseType](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest#xmlhttprequest-responsetype).
20001      *
20002      * @returns {HttpPromise} Returns a {@link ng.$q `Promise}` that will be resolved to a response object
20003      *                        when the request succeeds or fails.
20004      *
20005      *
20006      * @property {Array.<Object>} pendingRequests Array of config objects for currently pending
20007      *   requests. This is primarily meant to be used for debugging purposes.
20008      *
20009      *
20010      * @example
20011 <example module="httpExample">
20012 <file name="index.html">
20013   <div ng-controller="FetchController">
20014     <select ng-model="method" aria-label="Request method">
20015       <option>GET</option>
20016       <option>JSONP</option>
20017     </select>
20018     <input type="text" ng-model="url" size="80" aria-label="URL" />
20019     <button id="fetchbtn" ng-click="fetch()">fetch</button><br>
20020     <button id="samplegetbtn" ng-click="updateModel('GET', 'http-hello.html')">Sample GET</button>
20021     <button id="samplejsonpbtn"
20022       ng-click="updateModel('JSONP',
20023                     'https://angularjs.org/greet.php?callback=JSON_CALLBACK&name=Super%20Hero')">
20024       Sample JSONP
20025     </button>
20026     <button id="invalidjsonpbtn"
20027       ng-click="updateModel('JSONP', 'https://angularjs.org/doesntexist&callback=JSON_CALLBACK')">
20028         Invalid JSONP
20029       </button>
20030     <pre>http status code: {{status}}</pre>
20031     <pre>http response data: {{data}}</pre>
20032   </div>
20033 </file>
20034 <file name="script.js">
20035   angular.module('httpExample', [])
20036     .controller('FetchController', ['$scope', '$http', '$templateCache',
20037       function($scope, $http, $templateCache) {
20038         $scope.method = 'GET';
20039         $scope.url = 'http-hello.html';
20040
20041         $scope.fetch = function() {
20042           $scope.code = null;
20043           $scope.response = null;
20044
20045           $http({method: $scope.method, url: $scope.url, cache: $templateCache}).
20046             then(function(response) {
20047               $scope.status = response.status;
20048               $scope.data = response.data;
20049             }, function(response) {
20050               $scope.data = response.data || "Request failed";
20051               $scope.status = response.status;
20052           });
20053         };
20054
20055         $scope.updateModel = function(method, url) {
20056           $scope.method = method;
20057           $scope.url = url;
20058         };
20059       }]);
20060 </file>
20061 <file name="http-hello.html">
20062   Hello, $http!
20063 </file>
20064 <file name="protractor.js" type="protractor">
20065   var status = element(by.binding('status'));
20066   var data = element(by.binding('data'));
20067   var fetchBtn = element(by.id('fetchbtn'));
20068   var sampleGetBtn = element(by.id('samplegetbtn'));
20069   var sampleJsonpBtn = element(by.id('samplejsonpbtn'));
20070   var invalidJsonpBtn = element(by.id('invalidjsonpbtn'));
20071
20072   it('should make an xhr GET request', function() {
20073     sampleGetBtn.click();
20074     fetchBtn.click();
20075     expect(status.getText()).toMatch('200');
20076     expect(data.getText()).toMatch(/Hello, \$http!/);
20077   });
20078
20079 // Commented out due to flakes. See https://github.com/angular/angular.js/issues/9185
20080 // it('should make a JSONP request to angularjs.org', function() {
20081 //   sampleJsonpBtn.click();
20082 //   fetchBtn.click();
20083 //   expect(status.getText()).toMatch('200');
20084 //   expect(data.getText()).toMatch(/Super Hero!/);
20085 // });
20086
20087   it('should make JSONP request to invalid URL and invoke the error handler',
20088       function() {
20089     invalidJsonpBtn.click();
20090     fetchBtn.click();
20091     expect(status.getText()).toMatch('0');
20092     expect(data.getText()).toMatch('Request failed');
20093   });
20094 </file>
20095 </example>
20096      */
20097     function $http(requestConfig) {
20098
20099       if (!isObject(requestConfig)) {
20100         throw minErr('$http')('badreq', 'Http request configuration must be an object.  Received: {0}', requestConfig);
20101       }
20102
20103       if (!isString(requestConfig.url)) {
20104         throw minErr('$http')('badreq', 'Http request configuration url must be a string.  Received: {0}', requestConfig.url);
20105       }
20106
20107       var config = extend({
20108         method: 'get',
20109         transformRequest: defaults.transformRequest,
20110         transformResponse: defaults.transformResponse,
20111         paramSerializer: defaults.paramSerializer
20112       }, requestConfig);
20113
20114       config.headers = mergeHeaders(requestConfig);
20115       config.method = uppercase(config.method);
20116       config.paramSerializer = isString(config.paramSerializer) ?
20117         $injector.get(config.paramSerializer) : config.paramSerializer;
20118
20119       var serverRequest = function(config) {
20120         var headers = config.headers;
20121         var reqData = transformData(config.data, headersGetter(headers), undefined, config.transformRequest);
20122
20123         // strip content-type if data is undefined
20124         if (isUndefined(reqData)) {
20125           forEach(headers, function(value, header) {
20126             if (lowercase(header) === 'content-type') {
20127                 delete headers[header];
20128             }
20129           });
20130         }
20131
20132         if (isUndefined(config.withCredentials) && !isUndefined(defaults.withCredentials)) {
20133           config.withCredentials = defaults.withCredentials;
20134         }
20135
20136         // send request
20137         return sendReq(config, reqData).then(transformResponse, transformResponse);
20138       };
20139
20140       var chain = [serverRequest, undefined];
20141       var promise = $q.when(config);
20142
20143       // apply interceptors
20144       forEach(reversedInterceptors, function(interceptor) {
20145         if (interceptor.request || interceptor.requestError) {
20146           chain.unshift(interceptor.request, interceptor.requestError);
20147         }
20148         if (interceptor.response || interceptor.responseError) {
20149           chain.push(interceptor.response, interceptor.responseError);
20150         }
20151       });
20152
20153       while (chain.length) {
20154         var thenFn = chain.shift();
20155         var rejectFn = chain.shift();
20156
20157         promise = promise.then(thenFn, rejectFn);
20158       }
20159
20160       if (useLegacyPromise) {
20161         promise.success = function(fn) {
20162           assertArgFn(fn, 'fn');
20163
20164           promise.then(function(response) {
20165             fn(response.data, response.status, response.headers, config);
20166           });
20167           return promise;
20168         };
20169
20170         promise.error = function(fn) {
20171           assertArgFn(fn, 'fn');
20172
20173           promise.then(null, function(response) {
20174             fn(response.data, response.status, response.headers, config);
20175           });
20176           return promise;
20177         };
20178       } else {
20179         promise.success = $httpMinErrLegacyFn('success');
20180         promise.error = $httpMinErrLegacyFn('error');
20181       }
20182
20183       return promise;
20184
20185       function transformResponse(response) {
20186         // make a copy since the response must be cacheable
20187         var resp = extend({}, response);
20188         resp.data = transformData(response.data, response.headers, response.status,
20189                                   config.transformResponse);
20190         return (isSuccess(response.status))
20191           ? resp
20192           : $q.reject(resp);
20193       }
20194
20195       function executeHeaderFns(headers, config) {
20196         var headerContent, processedHeaders = {};
20197
20198         forEach(headers, function(headerFn, header) {
20199           if (isFunction(headerFn)) {
20200             headerContent = headerFn(config);
20201             if (headerContent != null) {
20202               processedHeaders[header] = headerContent;
20203             }
20204           } else {
20205             processedHeaders[header] = headerFn;
20206           }
20207         });
20208
20209         return processedHeaders;
20210       }
20211
20212       function mergeHeaders(config) {
20213         var defHeaders = defaults.headers,
20214             reqHeaders = extend({}, config.headers),
20215             defHeaderName, lowercaseDefHeaderName, reqHeaderName;
20216
20217         defHeaders = extend({}, defHeaders.common, defHeaders[lowercase(config.method)]);
20218
20219         // using for-in instead of forEach to avoid unnecessary iteration after header has been found
20220         defaultHeadersIteration:
20221         for (defHeaderName in defHeaders) {
20222           lowercaseDefHeaderName = lowercase(defHeaderName);
20223
20224           for (reqHeaderName in reqHeaders) {
20225             if (lowercase(reqHeaderName) === lowercaseDefHeaderName) {
20226               continue defaultHeadersIteration;
20227             }
20228           }
20229
20230           reqHeaders[defHeaderName] = defHeaders[defHeaderName];
20231         }
20232
20233         // execute if header value is a function for merged headers
20234         return executeHeaderFns(reqHeaders, shallowCopy(config));
20235       }
20236     }
20237
20238     $http.pendingRequests = [];
20239
20240     /**
20241      * @ngdoc method
20242      * @name $http#get
20243      *
20244      * @description
20245      * Shortcut method to perform `GET` request.
20246      *
20247      * @param {string} url Relative or absolute URL specifying the destination of the request
20248      * @param {Object=} config Optional configuration object
20249      * @returns {HttpPromise} Future object
20250      */
20251
20252     /**
20253      * @ngdoc method
20254      * @name $http#delete
20255      *
20256      * @description
20257      * Shortcut method to perform `DELETE` request.
20258      *
20259      * @param {string} url Relative or absolute URL specifying the destination of the request
20260      * @param {Object=} config Optional configuration object
20261      * @returns {HttpPromise} Future object
20262      */
20263
20264     /**
20265      * @ngdoc method
20266      * @name $http#head
20267      *
20268      * @description
20269      * Shortcut method to perform `HEAD` request.
20270      *
20271      * @param {string} url Relative or absolute URL specifying the destination of the request
20272      * @param {Object=} config Optional configuration object
20273      * @returns {HttpPromise} Future object
20274      */
20275
20276     /**
20277      * @ngdoc method
20278      * @name $http#jsonp
20279      *
20280      * @description
20281      * Shortcut method to perform `JSONP` request.
20282      *
20283      * @param {string} url Relative or absolute URL specifying the destination of the request.
20284      *                     The name of the callback should be the string `JSON_CALLBACK`.
20285      * @param {Object=} config Optional configuration object
20286      * @returns {HttpPromise} Future object
20287      */
20288     createShortMethods('get', 'delete', 'head', 'jsonp');
20289
20290     /**
20291      * @ngdoc method
20292      * @name $http#post
20293      *
20294      * @description
20295      * Shortcut method to perform `POST` request.
20296      *
20297      * @param {string} url Relative or absolute URL specifying the destination of the request
20298      * @param {*} data Request content
20299      * @param {Object=} config Optional configuration object
20300      * @returns {HttpPromise} Future object
20301      */
20302
20303     /**
20304      * @ngdoc method
20305      * @name $http#put
20306      *
20307      * @description
20308      * Shortcut method to perform `PUT` request.
20309      *
20310      * @param {string} url Relative or absolute URL specifying the destination of the request
20311      * @param {*} data Request content
20312      * @param {Object=} config Optional configuration object
20313      * @returns {HttpPromise} Future object
20314      */
20315
20316      /**
20317       * @ngdoc method
20318       * @name $http#patch
20319       *
20320       * @description
20321       * Shortcut method to perform `PATCH` request.
20322       *
20323       * @param {string} url Relative or absolute URL specifying the destination of the request
20324       * @param {*} data Request content
20325       * @param {Object=} config Optional configuration object
20326       * @returns {HttpPromise} Future object
20327       */
20328     createShortMethodsWithData('post', 'put', 'patch');
20329
20330         /**
20331          * @ngdoc property
20332          * @name $http#defaults
20333          *
20334          * @description
20335          * Runtime equivalent of the `$httpProvider.defaults` property. Allows configuration of
20336          * default headers, withCredentials as well as request and response transformations.
20337          *
20338          * See "Setting HTTP Headers" and "Transforming Requests and Responses" sections above.
20339          */
20340     $http.defaults = defaults;
20341
20342
20343     return $http;
20344
20345
20346     function createShortMethods(names) {
20347       forEach(arguments, function(name) {
20348         $http[name] = function(url, config) {
20349           return $http(extend({}, config || {}, {
20350             method: name,
20351             url: url
20352           }));
20353         };
20354       });
20355     }
20356
20357
20358     function createShortMethodsWithData(name) {
20359       forEach(arguments, function(name) {
20360         $http[name] = function(url, data, config) {
20361           return $http(extend({}, config || {}, {
20362             method: name,
20363             url: url,
20364             data: data
20365           }));
20366         };
20367       });
20368     }
20369
20370
20371     /**
20372      * Makes the request.
20373      *
20374      * !!! ACCESSES CLOSURE VARS:
20375      * $httpBackend, defaults, $log, $rootScope, defaultCache, $http.pendingRequests
20376      */
20377     function sendReq(config, reqData) {
20378       var deferred = $q.defer(),
20379           promise = deferred.promise,
20380           cache,
20381           cachedResp,
20382           reqHeaders = config.headers,
20383           url = buildUrl(config.url, config.paramSerializer(config.params));
20384
20385       $http.pendingRequests.push(config);
20386       promise.then(removePendingReq, removePendingReq);
20387
20388
20389       if ((config.cache || defaults.cache) && config.cache !== false &&
20390           (config.method === 'GET' || config.method === 'JSONP')) {
20391         cache = isObject(config.cache) ? config.cache
20392               : isObject(defaults.cache) ? defaults.cache
20393               : defaultCache;
20394       }
20395
20396       if (cache) {
20397         cachedResp = cache.get(url);
20398         if (isDefined(cachedResp)) {
20399           if (isPromiseLike(cachedResp)) {
20400             // cached request has already been sent, but there is no response yet
20401             cachedResp.then(resolvePromiseWithResult, resolvePromiseWithResult);
20402           } else {
20403             // serving from cache
20404             if (isArray(cachedResp)) {
20405               resolvePromise(cachedResp[1], cachedResp[0], shallowCopy(cachedResp[2]), cachedResp[3]);
20406             } else {
20407               resolvePromise(cachedResp, 200, {}, 'OK');
20408             }
20409           }
20410         } else {
20411           // put the promise for the non-transformed response into cache as a placeholder
20412           cache.put(url, promise);
20413         }
20414       }
20415
20416
20417       // if we won't have the response in cache, set the xsrf headers and
20418       // send the request to the backend
20419       if (isUndefined(cachedResp)) {
20420         var xsrfValue = urlIsSameOrigin(config.url)
20421             ? $$cookieReader()[config.xsrfCookieName || defaults.xsrfCookieName]
20422             : undefined;
20423         if (xsrfValue) {
20424           reqHeaders[(config.xsrfHeaderName || defaults.xsrfHeaderName)] = xsrfValue;
20425         }
20426
20427         $httpBackend(config.method, url, reqData, done, reqHeaders, config.timeout,
20428             config.withCredentials, config.responseType);
20429       }
20430
20431       return promise;
20432
20433
20434       /**
20435        * Callback registered to $httpBackend():
20436        *  - caches the response if desired
20437        *  - resolves the raw $http promise
20438        *  - calls $apply
20439        */
20440       function done(status, response, headersString, statusText) {
20441         if (cache) {
20442           if (isSuccess(status)) {
20443             cache.put(url, [status, response, parseHeaders(headersString), statusText]);
20444           } else {
20445             // remove promise from the cache
20446             cache.remove(url);
20447           }
20448         }
20449
20450         function resolveHttpPromise() {
20451           resolvePromise(response, status, headersString, statusText);
20452         }
20453
20454         if (useApplyAsync) {
20455           $rootScope.$applyAsync(resolveHttpPromise);
20456         } else {
20457           resolveHttpPromise();
20458           if (!$rootScope.$$phase) $rootScope.$apply();
20459         }
20460       }
20461
20462
20463       /**
20464        * Resolves the raw $http promise.
20465        */
20466       function resolvePromise(response, status, headers, statusText) {
20467         //status: HTTP response status code, 0, -1 (aborted by timeout / promise)
20468         status = status >= -1 ? status : 0;
20469
20470         (isSuccess(status) ? deferred.resolve : deferred.reject)({
20471           data: response,
20472           status: status,
20473           headers: headersGetter(headers),
20474           config: config,
20475           statusText: statusText
20476         });
20477       }
20478
20479       function resolvePromiseWithResult(result) {
20480         resolvePromise(result.data, result.status, shallowCopy(result.headers()), result.statusText);
20481       }
20482
20483       function removePendingReq() {
20484         var idx = $http.pendingRequests.indexOf(config);
20485         if (idx !== -1) $http.pendingRequests.splice(idx, 1);
20486       }
20487     }
20488
20489
20490     function buildUrl(url, serializedParams) {
20491       if (serializedParams.length > 0) {
20492         url += ((url.indexOf('?') == -1) ? '?' : '&') + serializedParams;
20493       }
20494       return url;
20495     }
20496   }];
20497 }
20498
20499 /**
20500  * @ngdoc service
20501  * @name $xhrFactory
20502  *
20503  * @description
20504  * Factory function used to create XMLHttpRequest objects.
20505  *
20506  * Replace or decorate this service to create your own custom XMLHttpRequest objects.
20507  *
20508  * ```
20509  * angular.module('myApp', [])
20510  * .factory('$xhrFactory', function() {
20511  *   return function createXhr(method, url) {
20512  *     return new window.XMLHttpRequest({mozSystem: true});
20513  *   };
20514  * });
20515  * ```
20516  *
20517  * @param {string} method HTTP method of the request (GET, POST, PUT, ..)
20518  * @param {string} url URL of the request.
20519  */
20520 function $xhrFactoryProvider() {
20521   this.$get = function() {
20522     return function createXhr() {
20523       return new window.XMLHttpRequest();
20524     };
20525   };
20526 }
20527
20528 /**
20529  * @ngdoc service
20530  * @name $httpBackend
20531  * @requires $window
20532  * @requires $document
20533  * @requires $xhrFactory
20534  *
20535  * @description
20536  * HTTP backend used by the {@link ng.$http service} that delegates to
20537  * XMLHttpRequest object or JSONP and deals with browser incompatibilities.
20538  *
20539  * You should never need to use this service directly, instead use the higher-level abstractions:
20540  * {@link ng.$http $http} or {@link ngResource.$resource $resource}.
20541  *
20542  * During testing this implementation is swapped with {@link ngMock.$httpBackend mock
20543  * $httpBackend} which can be trained with responses.
20544  */
20545 function $HttpBackendProvider() {
20546   this.$get = ['$browser', '$window', '$document', '$xhrFactory', function($browser, $window, $document, $xhrFactory) {
20547     return createHttpBackend($browser, $xhrFactory, $browser.defer, $window.angular.callbacks, $document[0]);
20548   }];
20549 }
20550
20551 function createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDocument) {
20552   // TODO(vojta): fix the signature
20553   return function(method, url, post, callback, headers, timeout, withCredentials, responseType) {
20554     $browser.$$incOutstandingRequestCount();
20555     url = url || $browser.url();
20556
20557     if (lowercase(method) == 'jsonp') {
20558       var callbackId = '_' + (callbacks.counter++).toString(36);
20559       callbacks[callbackId] = function(data) {
20560         callbacks[callbackId].data = data;
20561         callbacks[callbackId].called = true;
20562       };
20563
20564       var jsonpDone = jsonpReq(url.replace('JSON_CALLBACK', 'angular.callbacks.' + callbackId),
20565           callbackId, function(status, text) {
20566         completeRequest(callback, status, callbacks[callbackId].data, "", text);
20567         callbacks[callbackId] = noop;
20568       });
20569     } else {
20570
20571       var xhr = createXhr(method, url);
20572
20573       xhr.open(method, url, true);
20574       forEach(headers, function(value, key) {
20575         if (isDefined(value)) {
20576             xhr.setRequestHeader(key, value);
20577         }
20578       });
20579
20580       xhr.onload = function requestLoaded() {
20581         var statusText = xhr.statusText || '';
20582
20583         // responseText is the old-school way of retrieving response (supported by IE9)
20584         // response/responseType properties were introduced in XHR Level2 spec (supported by IE10)
20585         var response = ('response' in xhr) ? xhr.response : xhr.responseText;
20586
20587         // normalize IE9 bug (http://bugs.jquery.com/ticket/1450)
20588         var status = xhr.status === 1223 ? 204 : xhr.status;
20589
20590         // fix status code when it is 0 (0 status is undocumented).
20591         // Occurs when accessing file resources or on Android 4.1 stock browser
20592         // while retrieving files from application cache.
20593         if (status === 0) {
20594           status = response ? 200 : urlResolve(url).protocol == 'file' ? 404 : 0;
20595         }
20596
20597         completeRequest(callback,
20598             status,
20599             response,
20600             xhr.getAllResponseHeaders(),
20601             statusText);
20602       };
20603
20604       var requestError = function() {
20605         // The response is always empty
20606         // See https://xhr.spec.whatwg.org/#request-error-steps and https://fetch.spec.whatwg.org/#concept-network-error
20607         completeRequest(callback, -1, null, null, '');
20608       };
20609
20610       xhr.onerror = requestError;
20611       xhr.onabort = requestError;
20612
20613       if (withCredentials) {
20614         xhr.withCredentials = true;
20615       }
20616
20617       if (responseType) {
20618         try {
20619           xhr.responseType = responseType;
20620         } catch (e) {
20621           // WebKit added support for the json responseType value on 09/03/2013
20622           // https://bugs.webkit.org/show_bug.cgi?id=73648. Versions of Safari prior to 7 are
20623           // known to throw when setting the value "json" as the response type. Other older
20624           // browsers implementing the responseType
20625           //
20626           // The json response type can be ignored if not supported, because JSON payloads are
20627           // parsed on the client-side regardless.
20628           if (responseType !== 'json') {
20629             throw e;
20630           }
20631         }
20632       }
20633
20634       xhr.send(isUndefined(post) ? null : post);
20635     }
20636
20637     if (timeout > 0) {
20638       var timeoutId = $browserDefer(timeoutRequest, timeout);
20639     } else if (isPromiseLike(timeout)) {
20640       timeout.then(timeoutRequest);
20641     }
20642
20643
20644     function timeoutRequest() {
20645       jsonpDone && jsonpDone();
20646       xhr && xhr.abort();
20647     }
20648
20649     function completeRequest(callback, status, response, headersString, statusText) {
20650       // cancel timeout and subsequent timeout promise resolution
20651       if (isDefined(timeoutId)) {
20652         $browserDefer.cancel(timeoutId);
20653       }
20654       jsonpDone = xhr = null;
20655
20656       callback(status, response, headersString, statusText);
20657       $browser.$$completeOutstandingRequest(noop);
20658     }
20659   };
20660
20661   function jsonpReq(url, callbackId, done) {
20662     // we can't use jQuery/jqLite here because jQuery does crazy stuff with script elements, e.g.:
20663     // - fetches local scripts via XHR and evals them
20664     // - adds and immediately removes script elements from the document
20665     var script = rawDocument.createElement('script'), callback = null;
20666     script.type = "text/javascript";
20667     script.src = url;
20668     script.async = true;
20669
20670     callback = function(event) {
20671       removeEventListenerFn(script, "load", callback);
20672       removeEventListenerFn(script, "error", callback);
20673       rawDocument.body.removeChild(script);
20674       script = null;
20675       var status = -1;
20676       var text = "unknown";
20677
20678       if (event) {
20679         if (event.type === "load" && !callbacks[callbackId].called) {
20680           event = { type: "error" };
20681         }
20682         text = event.type;
20683         status = event.type === "error" ? 404 : 200;
20684       }
20685
20686       if (done) {
20687         done(status, text);
20688       }
20689     };
20690
20691     addEventListenerFn(script, "load", callback);
20692     addEventListenerFn(script, "error", callback);
20693     rawDocument.body.appendChild(script);
20694     return callback;
20695   }
20696 }
20697
20698 var $interpolateMinErr = angular.$interpolateMinErr = minErr('$interpolate');
20699 $interpolateMinErr.throwNoconcat = function(text) {
20700   throw $interpolateMinErr('noconcat',
20701       "Error while interpolating: {0}\nStrict Contextual Escaping disallows " +
20702       "interpolations that concatenate multiple expressions when a trusted value is " +
20703       "required.  See http://docs.angularjs.org/api/ng.$sce", text);
20704 };
20705
20706 $interpolateMinErr.interr = function(text, err) {
20707   return $interpolateMinErr('interr', "Can't interpolate: {0}\n{1}", text, err.toString());
20708 };
20709
20710 /**
20711  * @ngdoc provider
20712  * @name $interpolateProvider
20713  *
20714  * @description
20715  *
20716  * Used for configuring the interpolation markup. Defaults to `{{` and `}}`.
20717  *
20718  * <div class="alert alert-danger">
20719  * This feature is sometimes used to mix different markup languages, e.g. to wrap an Angular
20720  * template within a Python Jinja template (or any other template language). Mixing templating
20721  * languages is **very dangerous**. The embedding template language will not safely escape Angular
20722  * expressions, so any user-controlled values in the template will cause Cross Site Scripting (XSS)
20723  * security bugs!
20724  * </div>
20725  *
20726  * @example
20727 <example name="custom-interpolation-markup" module="customInterpolationApp">
20728 <file name="index.html">
20729 <script>
20730   var customInterpolationApp = angular.module('customInterpolationApp', []);
20731
20732   customInterpolationApp.config(function($interpolateProvider) {
20733     $interpolateProvider.startSymbol('//');
20734     $interpolateProvider.endSymbol('//');
20735   });
20736
20737
20738   customInterpolationApp.controller('DemoController', function() {
20739       this.label = "This binding is brought you by // interpolation symbols.";
20740   });
20741 </script>
20742 <div ng-controller="DemoController as demo">
20743     //demo.label//
20744 </div>
20745 </file>
20746 <file name="protractor.js" type="protractor">
20747   it('should interpolate binding with custom symbols', function() {
20748     expect(element(by.binding('demo.label')).getText()).toBe('This binding is brought you by // interpolation symbols.');
20749   });
20750 </file>
20751 </example>
20752  */
20753 function $InterpolateProvider() {
20754   var startSymbol = '{{';
20755   var endSymbol = '}}';
20756
20757   /**
20758    * @ngdoc method
20759    * @name $interpolateProvider#startSymbol
20760    * @description
20761    * Symbol to denote start of expression in the interpolated string. Defaults to `{{`.
20762    *
20763    * @param {string=} value new value to set the starting symbol to.
20764    * @returns {string|self} Returns the symbol when used as getter and self if used as setter.
20765    */
20766   this.startSymbol = function(value) {
20767     if (value) {
20768       startSymbol = value;
20769       return this;
20770     } else {
20771       return startSymbol;
20772     }
20773   };
20774
20775   /**
20776    * @ngdoc method
20777    * @name $interpolateProvider#endSymbol
20778    * @description
20779    * Symbol to denote the end of expression in the interpolated string. Defaults to `}}`.
20780    *
20781    * @param {string=} value new value to set the ending symbol to.
20782    * @returns {string|self} Returns the symbol when used as getter and self if used as setter.
20783    */
20784   this.endSymbol = function(value) {
20785     if (value) {
20786       endSymbol = value;
20787       return this;
20788     } else {
20789       return endSymbol;
20790     }
20791   };
20792
20793
20794   this.$get = ['$parse', '$exceptionHandler', '$sce', function($parse, $exceptionHandler, $sce) {
20795     var startSymbolLength = startSymbol.length,
20796         endSymbolLength = endSymbol.length,
20797         escapedStartRegexp = new RegExp(startSymbol.replace(/./g, escape), 'g'),
20798         escapedEndRegexp = new RegExp(endSymbol.replace(/./g, escape), 'g');
20799
20800     function escape(ch) {
20801       return '\\\\\\' + ch;
20802     }
20803
20804     function unescapeText(text) {
20805       return text.replace(escapedStartRegexp, startSymbol).
20806         replace(escapedEndRegexp, endSymbol);
20807     }
20808
20809     function stringify(value) {
20810       if (value == null) { // null || undefined
20811         return '';
20812       }
20813       switch (typeof value) {
20814         case 'string':
20815           break;
20816         case 'number':
20817           value = '' + value;
20818           break;
20819         default:
20820           value = toJson(value);
20821       }
20822
20823       return value;
20824     }
20825
20826     //TODO: this is the same as the constantWatchDelegate in parse.js
20827     function constantWatchDelegate(scope, listener, objectEquality, constantInterp) {
20828       var unwatch;
20829       return unwatch = scope.$watch(function constantInterpolateWatch(scope) {
20830         unwatch();
20831         return constantInterp(scope);
20832       }, listener, objectEquality);
20833     }
20834
20835     /**
20836      * @ngdoc service
20837      * @name $interpolate
20838      * @kind function
20839      *
20840      * @requires $parse
20841      * @requires $sce
20842      *
20843      * @description
20844      *
20845      * Compiles a string with markup into an interpolation function. This service is used by the
20846      * HTML {@link ng.$compile $compile} service for data binding. See
20847      * {@link ng.$interpolateProvider $interpolateProvider} for configuring the
20848      * interpolation markup.
20849      *
20850      *
20851      * ```js
20852      *   var $interpolate = ...; // injected
20853      *   var exp = $interpolate('Hello {{name | uppercase}}!');
20854      *   expect(exp({name:'Angular'})).toEqual('Hello ANGULAR!');
20855      * ```
20856      *
20857      * `$interpolate` takes an optional fourth argument, `allOrNothing`. If `allOrNothing` is
20858      * `true`, the interpolation function will return `undefined` unless all embedded expressions
20859      * evaluate to a value other than `undefined`.
20860      *
20861      * ```js
20862      *   var $interpolate = ...; // injected
20863      *   var context = {greeting: 'Hello', name: undefined };
20864      *
20865      *   // default "forgiving" mode
20866      *   var exp = $interpolate('{{greeting}} {{name}}!');
20867      *   expect(exp(context)).toEqual('Hello !');
20868      *
20869      *   // "allOrNothing" mode
20870      *   exp = $interpolate('{{greeting}} {{name}}!', false, null, true);
20871      *   expect(exp(context)).toBeUndefined();
20872      *   context.name = 'Angular';
20873      *   expect(exp(context)).toEqual('Hello Angular!');
20874      * ```
20875      *
20876      * `allOrNothing` is useful for interpolating URLs. `ngSrc` and `ngSrcset` use this behavior.
20877      *
20878      * ####Escaped Interpolation
20879      * $interpolate provides a mechanism for escaping interpolation markers. Start and end markers
20880      * can be escaped by preceding each of their characters with a REVERSE SOLIDUS U+005C (backslash).
20881      * It will be rendered as a regular start/end marker, and will not be interpreted as an expression
20882      * or binding.
20883      *
20884      * This enables web-servers to prevent script injection attacks and defacing attacks, to some
20885      * degree, while also enabling code examples to work without relying on the
20886      * {@link ng.directive:ngNonBindable ngNonBindable} directive.
20887      *
20888      * **For security purposes, it is strongly encouraged that web servers escape user-supplied data,
20889      * replacing angle brackets (&lt;, &gt;) with &amp;lt; and &amp;gt; respectively, and replacing all
20890      * interpolation start/end markers with their escaped counterparts.**
20891      *
20892      * Escaped interpolation markers are only replaced with the actual interpolation markers in rendered
20893      * output when the $interpolate service processes the text. So, for HTML elements interpolated
20894      * by {@link ng.$compile $compile}, or otherwise interpolated with the `mustHaveExpression` parameter
20895      * set to `true`, the interpolated text must contain an unescaped interpolation expression. As such,
20896      * this is typically useful only when user-data is used in rendering a template from the server, or
20897      * when otherwise untrusted data is used by a directive.
20898      *
20899      * <example>
20900      *  <file name="index.html">
20901      *    <div ng-init="username='A user'">
20902      *      <p ng-init="apptitle='Escaping demo'">{{apptitle}}: \{\{ username = "defaced value"; \}\}
20903      *        </p>
20904      *      <p><strong>{{username}}</strong> attempts to inject code which will deface the
20905      *        application, but fails to accomplish their task, because the server has correctly
20906      *        escaped the interpolation start/end markers with REVERSE SOLIDUS U+005C (backslash)
20907      *        characters.</p>
20908      *      <p>Instead, the result of the attempted script injection is visible, and can be removed
20909      *        from the database by an administrator.</p>
20910      *    </div>
20911      *  </file>
20912      * </example>
20913      *
20914      * @param {string} text The text with markup to interpolate.
20915      * @param {boolean=} mustHaveExpression if set to true then the interpolation string must have
20916      *    embedded expression in order to return an interpolation function. Strings with no
20917      *    embedded expression will return null for the interpolation function.
20918      * @param {string=} trustedContext when provided, the returned function passes the interpolated
20919      *    result through {@link ng.$sce#getTrusted $sce.getTrusted(interpolatedResult,
20920      *    trustedContext)} before returning it.  Refer to the {@link ng.$sce $sce} service that
20921      *    provides Strict Contextual Escaping for details.
20922      * @param {boolean=} allOrNothing if `true`, then the returned function returns undefined
20923      *    unless all embedded expressions evaluate to a value other than `undefined`.
20924      * @returns {function(context)} an interpolation function which is used to compute the
20925      *    interpolated string. The function has these parameters:
20926      *
20927      * - `context`: evaluation context for all expressions embedded in the interpolated text
20928      */
20929     function $interpolate(text, mustHaveExpression, trustedContext, allOrNothing) {
20930       // Provide a quick exit and simplified result function for text with no interpolation
20931       if (!text.length || text.indexOf(startSymbol) === -1) {
20932         var constantInterp;
20933         if (!mustHaveExpression) {
20934           var unescapedText = unescapeText(text);
20935           constantInterp = valueFn(unescapedText);
20936           constantInterp.exp = text;
20937           constantInterp.expressions = [];
20938           constantInterp.$$watchDelegate = constantWatchDelegate;
20939         }
20940         return constantInterp;
20941       }
20942
20943       allOrNothing = !!allOrNothing;
20944       var startIndex,
20945           endIndex,
20946           index = 0,
20947           expressions = [],
20948           parseFns = [],
20949           textLength = text.length,
20950           exp,
20951           concat = [],
20952           expressionPositions = [];
20953
20954       while (index < textLength) {
20955         if (((startIndex = text.indexOf(startSymbol, index)) != -1) &&
20956              ((endIndex = text.indexOf(endSymbol, startIndex + startSymbolLength)) != -1)) {
20957           if (index !== startIndex) {
20958             concat.push(unescapeText(text.substring(index, startIndex)));
20959           }
20960           exp = text.substring(startIndex + startSymbolLength, endIndex);
20961           expressions.push(exp);
20962           parseFns.push($parse(exp, parseStringifyInterceptor));
20963           index = endIndex + endSymbolLength;
20964           expressionPositions.push(concat.length);
20965           concat.push('');
20966         } else {
20967           // we did not find an interpolation, so we have to add the remainder to the separators array
20968           if (index !== textLength) {
20969             concat.push(unescapeText(text.substring(index)));
20970           }
20971           break;
20972         }
20973       }
20974
20975       // Concatenating expressions makes it hard to reason about whether some combination of
20976       // concatenated values are unsafe to use and could easily lead to XSS.  By requiring that a
20977       // single expression be used for iframe[src], object[src], etc., we ensure that the value
20978       // that's used is assigned or constructed by some JS code somewhere that is more testable or
20979       // make it obvious that you bound the value to some user controlled value.  This helps reduce
20980       // the load when auditing for XSS issues.
20981       if (trustedContext && concat.length > 1) {
20982           $interpolateMinErr.throwNoconcat(text);
20983       }
20984
20985       if (!mustHaveExpression || expressions.length) {
20986         var compute = function(values) {
20987           for (var i = 0, ii = expressions.length; i < ii; i++) {
20988             if (allOrNothing && isUndefined(values[i])) return;
20989             concat[expressionPositions[i]] = values[i];
20990           }
20991           return concat.join('');
20992         };
20993
20994         var getValue = function(value) {
20995           return trustedContext ?
20996             $sce.getTrusted(trustedContext, value) :
20997             $sce.valueOf(value);
20998         };
20999
21000         return extend(function interpolationFn(context) {
21001             var i = 0;
21002             var ii = expressions.length;
21003             var values = new Array(ii);
21004
21005             try {
21006               for (; i < ii; i++) {
21007                 values[i] = parseFns[i](context);
21008               }
21009
21010               return compute(values);
21011             } catch (err) {
21012               $exceptionHandler($interpolateMinErr.interr(text, err));
21013             }
21014
21015           }, {
21016           // all of these properties are undocumented for now
21017           exp: text, //just for compatibility with regular watchers created via $watch
21018           expressions: expressions,
21019           $$watchDelegate: function(scope, listener) {
21020             var lastValue;
21021             return scope.$watchGroup(parseFns, function interpolateFnWatcher(values, oldValues) {
21022               var currValue = compute(values);
21023               if (isFunction(listener)) {
21024                 listener.call(this, currValue, values !== oldValues ? lastValue : currValue, scope);
21025               }
21026               lastValue = currValue;
21027             });
21028           }
21029         });
21030       }
21031
21032       function parseStringifyInterceptor(value) {
21033         try {
21034           value = getValue(value);
21035           return allOrNothing && !isDefined(value) ? value : stringify(value);
21036         } catch (err) {
21037           $exceptionHandler($interpolateMinErr.interr(text, err));
21038         }
21039       }
21040     }
21041
21042
21043     /**
21044      * @ngdoc method
21045      * @name $interpolate#startSymbol
21046      * @description
21047      * Symbol to denote the start of expression in the interpolated string. Defaults to `{{`.
21048      *
21049      * Use {@link ng.$interpolateProvider#startSymbol `$interpolateProvider.startSymbol`} to change
21050      * the symbol.
21051      *
21052      * @returns {string} start symbol.
21053      */
21054     $interpolate.startSymbol = function() {
21055       return startSymbol;
21056     };
21057
21058
21059     /**
21060      * @ngdoc method
21061      * @name $interpolate#endSymbol
21062      * @description
21063      * Symbol to denote the end of expression in the interpolated string. Defaults to `}}`.
21064      *
21065      * Use {@link ng.$interpolateProvider#endSymbol `$interpolateProvider.endSymbol`} to change
21066      * the symbol.
21067      *
21068      * @returns {string} end symbol.
21069      */
21070     $interpolate.endSymbol = function() {
21071       return endSymbol;
21072     };
21073
21074     return $interpolate;
21075   }];
21076 }
21077
21078 function $IntervalProvider() {
21079   this.$get = ['$rootScope', '$window', '$q', '$$q', '$browser',
21080        function($rootScope,   $window,   $q,   $$q,   $browser) {
21081     var intervals = {};
21082
21083
21084      /**
21085       * @ngdoc service
21086       * @name $interval
21087       *
21088       * @description
21089       * Angular's wrapper for `window.setInterval`. The `fn` function is executed every `delay`
21090       * milliseconds.
21091       *
21092       * The return value of registering an interval function is a promise. This promise will be
21093       * notified upon each tick of the interval, and will be resolved after `count` iterations, or
21094       * run indefinitely if `count` is not defined. The value of the notification will be the
21095       * number of iterations that have run.
21096       * To cancel an interval, call `$interval.cancel(promise)`.
21097       *
21098       * In tests you can use {@link ngMock.$interval#flush `$interval.flush(millis)`} to
21099       * move forward by `millis` milliseconds and trigger any functions scheduled to run in that
21100       * time.
21101       *
21102       * <div class="alert alert-warning">
21103       * **Note**: Intervals created by this service must be explicitly destroyed when you are finished
21104       * with them.  In particular they are not automatically destroyed when a controller's scope or a
21105       * directive's element are destroyed.
21106       * You should take this into consideration and make sure to always cancel the interval at the
21107       * appropriate moment.  See the example below for more details on how and when to do this.
21108       * </div>
21109       *
21110       * @param {function()} fn A function that should be called repeatedly.
21111       * @param {number} delay Number of milliseconds between each function call.
21112       * @param {number=} [count=0] Number of times to repeat. If not set, or 0, will repeat
21113       *   indefinitely.
21114       * @param {boolean=} [invokeApply=true] If set to `false` skips model dirty checking, otherwise
21115       *   will invoke `fn` within the {@link ng.$rootScope.Scope#$apply $apply} block.
21116       * @param {...*=} Pass additional parameters to the executed function.
21117       * @returns {promise} A promise which will be notified on each iteration.
21118       *
21119       * @example
21120       * <example module="intervalExample">
21121       * <file name="index.html">
21122       *   <script>
21123       *     angular.module('intervalExample', [])
21124       *       .controller('ExampleController', ['$scope', '$interval',
21125       *         function($scope, $interval) {
21126       *           $scope.format = 'M/d/yy h:mm:ss a';
21127       *           $scope.blood_1 = 100;
21128       *           $scope.blood_2 = 120;
21129       *
21130       *           var stop;
21131       *           $scope.fight = function() {
21132       *             // Don't start a new fight if we are already fighting
21133       *             if ( angular.isDefined(stop) ) return;
21134       *
21135       *             stop = $interval(function() {
21136       *               if ($scope.blood_1 > 0 && $scope.blood_2 > 0) {
21137       *                 $scope.blood_1 = $scope.blood_1 - 3;
21138       *                 $scope.blood_2 = $scope.blood_2 - 4;
21139       *               } else {
21140       *                 $scope.stopFight();
21141       *               }
21142       *             }, 100);
21143       *           };
21144       *
21145       *           $scope.stopFight = function() {
21146       *             if (angular.isDefined(stop)) {
21147       *               $interval.cancel(stop);
21148       *               stop = undefined;
21149       *             }
21150       *           };
21151       *
21152       *           $scope.resetFight = function() {
21153       *             $scope.blood_1 = 100;
21154       *             $scope.blood_2 = 120;
21155       *           };
21156       *
21157       *           $scope.$on('$destroy', function() {
21158       *             // Make sure that the interval is destroyed too
21159       *             $scope.stopFight();
21160       *           });
21161       *         }])
21162       *       // Register the 'myCurrentTime' directive factory method.
21163       *       // We inject $interval and dateFilter service since the factory method is DI.
21164       *       .directive('myCurrentTime', ['$interval', 'dateFilter',
21165       *         function($interval, dateFilter) {
21166       *           // return the directive link function. (compile function not needed)
21167       *           return function(scope, element, attrs) {
21168       *             var format,  // date format
21169       *                 stopTime; // so that we can cancel the time updates
21170       *
21171       *             // used to update the UI
21172       *             function updateTime() {
21173       *               element.text(dateFilter(new Date(), format));
21174       *             }
21175       *
21176       *             // watch the expression, and update the UI on change.
21177       *             scope.$watch(attrs.myCurrentTime, function(value) {
21178       *               format = value;
21179       *               updateTime();
21180       *             });
21181       *
21182       *             stopTime = $interval(updateTime, 1000);
21183       *
21184       *             // listen on DOM destroy (removal) event, and cancel the next UI update
21185       *             // to prevent updating time after the DOM element was removed.
21186       *             element.on('$destroy', function() {
21187       *               $interval.cancel(stopTime);
21188       *             });
21189       *           }
21190       *         }]);
21191       *   </script>
21192       *
21193       *   <div>
21194       *     <div ng-controller="ExampleController">
21195       *       <label>Date format: <input ng-model="format"></label> <hr/>
21196       *       Current time is: <span my-current-time="format"></span>
21197       *       <hr/>
21198       *       Blood 1 : <font color='red'>{{blood_1}}</font>
21199       *       Blood 2 : <font color='red'>{{blood_2}}</font>
21200       *       <button type="button" data-ng-click="fight()">Fight</button>
21201       *       <button type="button" data-ng-click="stopFight()">StopFight</button>
21202       *       <button type="button" data-ng-click="resetFight()">resetFight</button>
21203       *     </div>
21204       *   </div>
21205       *
21206       * </file>
21207       * </example>
21208       */
21209     function interval(fn, delay, count, invokeApply) {
21210       var hasParams = arguments.length > 4,
21211           args = hasParams ? sliceArgs(arguments, 4) : [],
21212           setInterval = $window.setInterval,
21213           clearInterval = $window.clearInterval,
21214           iteration = 0,
21215           skipApply = (isDefined(invokeApply) && !invokeApply),
21216           deferred = (skipApply ? $$q : $q).defer(),
21217           promise = deferred.promise;
21218
21219       count = isDefined(count) ? count : 0;
21220
21221       promise.$$intervalId = setInterval(function tick() {
21222         if (skipApply) {
21223           $browser.defer(callback);
21224         } else {
21225           $rootScope.$evalAsync(callback);
21226         }
21227         deferred.notify(iteration++);
21228
21229         if (count > 0 && iteration >= count) {
21230           deferred.resolve(iteration);
21231           clearInterval(promise.$$intervalId);
21232           delete intervals[promise.$$intervalId];
21233         }
21234
21235         if (!skipApply) $rootScope.$apply();
21236
21237       }, delay);
21238
21239       intervals[promise.$$intervalId] = deferred;
21240
21241       return promise;
21242
21243       function callback() {
21244         if (!hasParams) {
21245           fn(iteration);
21246         } else {
21247           fn.apply(null, args);
21248         }
21249       }
21250     }
21251
21252
21253      /**
21254       * @ngdoc method
21255       * @name $interval#cancel
21256       *
21257       * @description
21258       * Cancels a task associated with the `promise`.
21259       *
21260       * @param {Promise=} promise returned by the `$interval` function.
21261       * @returns {boolean} Returns `true` if the task was successfully canceled.
21262       */
21263     interval.cancel = function(promise) {
21264       if (promise && promise.$$intervalId in intervals) {
21265         intervals[promise.$$intervalId].reject('canceled');
21266         $window.clearInterval(promise.$$intervalId);
21267         delete intervals[promise.$$intervalId];
21268         return true;
21269       }
21270       return false;
21271     };
21272
21273     return interval;
21274   }];
21275 }
21276
21277 /**
21278  * @ngdoc service
21279  * @name $locale
21280  *
21281  * @description
21282  * $locale service provides localization rules for various Angular components. As of right now the
21283  * only public api is:
21284  *
21285  * * `id` – `{string}` – locale id formatted as `languageId-countryId` (e.g. `en-us`)
21286  */
21287
21288 var PATH_MATCH = /^([^\?#]*)(\?([^#]*))?(#(.*))?$/,
21289     DEFAULT_PORTS = {'http': 80, 'https': 443, 'ftp': 21};
21290 var $locationMinErr = minErr('$location');
21291
21292
21293 /**
21294  * Encode path using encodeUriSegment, ignoring forward slashes
21295  *
21296  * @param {string} path Path to encode
21297  * @returns {string}
21298  */
21299 function encodePath(path) {
21300   var segments = path.split('/'),
21301       i = segments.length;
21302
21303   while (i--) {
21304     segments[i] = encodeUriSegment(segments[i]);
21305   }
21306
21307   return segments.join('/');
21308 }
21309
21310 function parseAbsoluteUrl(absoluteUrl, locationObj) {
21311   var parsedUrl = urlResolve(absoluteUrl);
21312
21313   locationObj.$$protocol = parsedUrl.protocol;
21314   locationObj.$$host = parsedUrl.hostname;
21315   locationObj.$$port = toInt(parsedUrl.port) || DEFAULT_PORTS[parsedUrl.protocol] || null;
21316 }
21317
21318
21319 function parseAppUrl(relativeUrl, locationObj) {
21320   var prefixed = (relativeUrl.charAt(0) !== '/');
21321   if (prefixed) {
21322     relativeUrl = '/' + relativeUrl;
21323   }
21324   var match = urlResolve(relativeUrl);
21325   locationObj.$$path = decodeURIComponent(prefixed && match.pathname.charAt(0) === '/' ?
21326       match.pathname.substring(1) : match.pathname);
21327   locationObj.$$search = parseKeyValue(match.search);
21328   locationObj.$$hash = decodeURIComponent(match.hash);
21329
21330   // make sure path starts with '/';
21331   if (locationObj.$$path && locationObj.$$path.charAt(0) != '/') {
21332     locationObj.$$path = '/' + locationObj.$$path;
21333   }
21334 }
21335
21336
21337 /**
21338  *
21339  * @param {string} begin
21340  * @param {string} whole
21341  * @returns {string} returns text from whole after begin or undefined if it does not begin with
21342  *                   expected string.
21343  */
21344 function beginsWith(begin, whole) {
21345   if (whole.indexOf(begin) === 0) {
21346     return whole.substr(begin.length);
21347   }
21348 }
21349
21350
21351 function stripHash(url) {
21352   var index = url.indexOf('#');
21353   return index == -1 ? url : url.substr(0, index);
21354 }
21355
21356 function trimEmptyHash(url) {
21357   return url.replace(/(#.+)|#$/, '$1');
21358 }
21359
21360
21361 function stripFile(url) {
21362   return url.substr(0, stripHash(url).lastIndexOf('/') + 1);
21363 }
21364
21365 /* return the server only (scheme://host:port) */
21366 function serverBase(url) {
21367   return url.substring(0, url.indexOf('/', url.indexOf('//') + 2));
21368 }
21369
21370
21371 /**
21372  * LocationHtml5Url represents an url
21373  * This object is exposed as $location service when HTML5 mode is enabled and supported
21374  *
21375  * @constructor
21376  * @param {string} appBase application base URL
21377  * @param {string} appBaseNoFile application base URL stripped of any filename
21378  * @param {string} basePrefix url path prefix
21379  */
21380 function LocationHtml5Url(appBase, appBaseNoFile, basePrefix) {
21381   this.$$html5 = true;
21382   basePrefix = basePrefix || '';
21383   parseAbsoluteUrl(appBase, this);
21384
21385
21386   /**
21387    * Parse given html5 (regular) url string into properties
21388    * @param {string} url HTML5 url
21389    * @private
21390    */
21391   this.$$parse = function(url) {
21392     var pathUrl = beginsWith(appBaseNoFile, url);
21393     if (!isString(pathUrl)) {
21394       throw $locationMinErr('ipthprfx', 'Invalid url "{0}", missing path prefix "{1}".', url,
21395           appBaseNoFile);
21396     }
21397
21398     parseAppUrl(pathUrl, this);
21399
21400     if (!this.$$path) {
21401       this.$$path = '/';
21402     }
21403
21404     this.$$compose();
21405   };
21406
21407   /**
21408    * Compose url and update `absUrl` property
21409    * @private
21410    */
21411   this.$$compose = function() {
21412     var search = toKeyValue(this.$$search),
21413         hash = this.$$hash ? '#' + encodeUriSegment(this.$$hash) : '';
21414
21415     this.$$url = encodePath(this.$$path) + (search ? '?' + search : '') + hash;
21416     this.$$absUrl = appBaseNoFile + this.$$url.substr(1); // first char is always '/'
21417   };
21418
21419   this.$$parseLinkUrl = function(url, relHref) {
21420     if (relHref && relHref[0] === '#') {
21421       // special case for links to hash fragments:
21422       // keep the old url and only replace the hash fragment
21423       this.hash(relHref.slice(1));
21424       return true;
21425     }
21426     var appUrl, prevAppUrl;
21427     var rewrittenUrl;
21428
21429     if (isDefined(appUrl = beginsWith(appBase, url))) {
21430       prevAppUrl = appUrl;
21431       if (isDefined(appUrl = beginsWith(basePrefix, appUrl))) {
21432         rewrittenUrl = appBaseNoFile + (beginsWith('/', appUrl) || appUrl);
21433       } else {
21434         rewrittenUrl = appBase + prevAppUrl;
21435       }
21436     } else if (isDefined(appUrl = beginsWith(appBaseNoFile, url))) {
21437       rewrittenUrl = appBaseNoFile + appUrl;
21438     } else if (appBaseNoFile == url + '/') {
21439       rewrittenUrl = appBaseNoFile;
21440     }
21441     if (rewrittenUrl) {
21442       this.$$parse(rewrittenUrl);
21443     }
21444     return !!rewrittenUrl;
21445   };
21446 }
21447
21448
21449 /**
21450  * LocationHashbangUrl represents url
21451  * This object is exposed as $location service when developer doesn't opt into html5 mode.
21452  * It also serves as the base class for html5 mode fallback on legacy browsers.
21453  *
21454  * @constructor
21455  * @param {string} appBase application base URL
21456  * @param {string} appBaseNoFile application base URL stripped of any filename
21457  * @param {string} hashPrefix hashbang prefix
21458  */
21459 function LocationHashbangUrl(appBase, appBaseNoFile, hashPrefix) {
21460
21461   parseAbsoluteUrl(appBase, this);
21462
21463
21464   /**
21465    * Parse given hashbang url into properties
21466    * @param {string} url Hashbang url
21467    * @private
21468    */
21469   this.$$parse = function(url) {
21470     var withoutBaseUrl = beginsWith(appBase, url) || beginsWith(appBaseNoFile, url);
21471     var withoutHashUrl;
21472
21473     if (!isUndefined(withoutBaseUrl) && withoutBaseUrl.charAt(0) === '#') {
21474
21475       // The rest of the url starts with a hash so we have
21476       // got either a hashbang path or a plain hash fragment
21477       withoutHashUrl = beginsWith(hashPrefix, withoutBaseUrl);
21478       if (isUndefined(withoutHashUrl)) {
21479         // There was no hashbang prefix so we just have a hash fragment
21480         withoutHashUrl = withoutBaseUrl;
21481       }
21482
21483     } else {
21484       // There was no hashbang path nor hash fragment:
21485       // If we are in HTML5 mode we use what is left as the path;
21486       // Otherwise we ignore what is left
21487       if (this.$$html5) {
21488         withoutHashUrl = withoutBaseUrl;
21489       } else {
21490         withoutHashUrl = '';
21491         if (isUndefined(withoutBaseUrl)) {
21492           appBase = url;
21493           this.replace();
21494         }
21495       }
21496     }
21497
21498     parseAppUrl(withoutHashUrl, this);
21499
21500     this.$$path = removeWindowsDriveName(this.$$path, withoutHashUrl, appBase);
21501
21502     this.$$compose();
21503
21504     /*
21505      * In Windows, on an anchor node on documents loaded from
21506      * the filesystem, the browser will return a pathname
21507      * prefixed with the drive name ('/C:/path') when a
21508      * pathname without a drive is set:
21509      *  * a.setAttribute('href', '/foo')
21510      *   * a.pathname === '/C:/foo' //true
21511      *
21512      * Inside of Angular, we're always using pathnames that
21513      * do not include drive names for routing.
21514      */
21515     function removeWindowsDriveName(path, url, base) {
21516       /*
21517       Matches paths for file protocol on windows,
21518       such as /C:/foo/bar, and captures only /foo/bar.
21519       */
21520       var windowsFilePathExp = /^\/[A-Z]:(\/.*)/;
21521
21522       var firstPathSegmentMatch;
21523
21524       //Get the relative path from the input URL.
21525       if (url.indexOf(base) === 0) {
21526         url = url.replace(base, '');
21527       }
21528
21529       // The input URL intentionally contains a first path segment that ends with a colon.
21530       if (windowsFilePathExp.exec(url)) {
21531         return path;
21532       }
21533
21534       firstPathSegmentMatch = windowsFilePathExp.exec(path);
21535       return firstPathSegmentMatch ? firstPathSegmentMatch[1] : path;
21536     }
21537   };
21538
21539   /**
21540    * Compose hashbang url and update `absUrl` property
21541    * @private
21542    */
21543   this.$$compose = function() {
21544     var search = toKeyValue(this.$$search),
21545         hash = this.$$hash ? '#' + encodeUriSegment(this.$$hash) : '';
21546
21547     this.$$url = encodePath(this.$$path) + (search ? '?' + search : '') + hash;
21548     this.$$absUrl = appBase + (this.$$url ? hashPrefix + this.$$url : '');
21549   };
21550
21551   this.$$parseLinkUrl = function(url, relHref) {
21552     if (stripHash(appBase) == stripHash(url)) {
21553       this.$$parse(url);
21554       return true;
21555     }
21556     return false;
21557   };
21558 }
21559
21560
21561 /**
21562  * LocationHashbangUrl represents url
21563  * This object is exposed as $location service when html5 history api is enabled but the browser
21564  * does not support it.
21565  *
21566  * @constructor
21567  * @param {string} appBase application base URL
21568  * @param {string} appBaseNoFile application base URL stripped of any filename
21569  * @param {string} hashPrefix hashbang prefix
21570  */
21571 function LocationHashbangInHtml5Url(appBase, appBaseNoFile, hashPrefix) {
21572   this.$$html5 = true;
21573   LocationHashbangUrl.apply(this, arguments);
21574
21575   this.$$parseLinkUrl = function(url, relHref) {
21576     if (relHref && relHref[0] === '#') {
21577       // special case for links to hash fragments:
21578       // keep the old url and only replace the hash fragment
21579       this.hash(relHref.slice(1));
21580       return true;
21581     }
21582
21583     var rewrittenUrl;
21584     var appUrl;
21585
21586     if (appBase == stripHash(url)) {
21587       rewrittenUrl = url;
21588     } else if ((appUrl = beginsWith(appBaseNoFile, url))) {
21589       rewrittenUrl = appBase + hashPrefix + appUrl;
21590     } else if (appBaseNoFile === url + '/') {
21591       rewrittenUrl = appBaseNoFile;
21592     }
21593     if (rewrittenUrl) {
21594       this.$$parse(rewrittenUrl);
21595     }
21596     return !!rewrittenUrl;
21597   };
21598
21599   this.$$compose = function() {
21600     var search = toKeyValue(this.$$search),
21601         hash = this.$$hash ? '#' + encodeUriSegment(this.$$hash) : '';
21602
21603     this.$$url = encodePath(this.$$path) + (search ? '?' + search : '') + hash;
21604     // include hashPrefix in $$absUrl when $$url is empty so IE9 does not reload page because of removal of '#'
21605     this.$$absUrl = appBase + hashPrefix + this.$$url;
21606   };
21607
21608 }
21609
21610
21611 var locationPrototype = {
21612
21613   /**
21614    * Are we in html5 mode?
21615    * @private
21616    */
21617   $$html5: false,
21618
21619   /**
21620    * Has any change been replacing?
21621    * @private
21622    */
21623   $$replace: false,
21624
21625   /**
21626    * @ngdoc method
21627    * @name $location#absUrl
21628    *
21629    * @description
21630    * This method is getter only.
21631    *
21632    * Return full url representation with all segments encoded according to rules specified in
21633    * [RFC 3986](http://www.ietf.org/rfc/rfc3986.txt).
21634    *
21635    *
21636    * ```js
21637    * // given url http://example.com/#/some/path?foo=bar&baz=xoxo
21638    * var absUrl = $location.absUrl();
21639    * // => "http://example.com/#/some/path?foo=bar&baz=xoxo"
21640    * ```
21641    *
21642    * @return {string} full url
21643    */
21644   absUrl: locationGetter('$$absUrl'),
21645
21646   /**
21647    * @ngdoc method
21648    * @name $location#url
21649    *
21650    * @description
21651    * This method is getter / setter.
21652    *
21653    * Return url (e.g. `/path?a=b#hash`) when called without any parameter.
21654    *
21655    * Change path, search and hash, when called with parameter and return `$location`.
21656    *
21657    *
21658    * ```js
21659    * // given url http://example.com/#/some/path?foo=bar&baz=xoxo
21660    * var url = $location.url();
21661    * // => "/some/path?foo=bar&baz=xoxo"
21662    * ```
21663    *
21664    * @param {string=} url New url without base prefix (e.g. `/path?a=b#hash`)
21665    * @return {string} url
21666    */
21667   url: function(url) {
21668     if (isUndefined(url)) {
21669       return this.$$url;
21670     }
21671
21672     var match = PATH_MATCH.exec(url);
21673     if (match[1] || url === '') this.path(decodeURIComponent(match[1]));
21674     if (match[2] || match[1] || url === '') this.search(match[3] || '');
21675     this.hash(match[5] || '');
21676
21677     return this;
21678   },
21679
21680   /**
21681    * @ngdoc method
21682    * @name $location#protocol
21683    *
21684    * @description
21685    * This method is getter only.
21686    *
21687    * Return protocol of current url.
21688    *
21689    *
21690    * ```js
21691    * // given url http://example.com/#/some/path?foo=bar&baz=xoxo
21692    * var protocol = $location.protocol();
21693    * // => "http"
21694    * ```
21695    *
21696    * @return {string} protocol of current url
21697    */
21698   protocol: locationGetter('$$protocol'),
21699
21700   /**
21701    * @ngdoc method
21702    * @name $location#host
21703    *
21704    * @description
21705    * This method is getter only.
21706    *
21707    * Return host of current url.
21708    *
21709    * Note: compared to the non-angular version `location.host` which returns `hostname:port`, this returns the `hostname` portion only.
21710    *
21711    *
21712    * ```js
21713    * // given url http://example.com/#/some/path?foo=bar&baz=xoxo
21714    * var host = $location.host();
21715    * // => "example.com"
21716    *
21717    * // given url http://user:password@example.com:8080/#/some/path?foo=bar&baz=xoxo
21718    * host = $location.host();
21719    * // => "example.com"
21720    * host = location.host;
21721    * // => "example.com:8080"
21722    * ```
21723    *
21724    * @return {string} host of current url.
21725    */
21726   host: locationGetter('$$host'),
21727
21728   /**
21729    * @ngdoc method
21730    * @name $location#port
21731    *
21732    * @description
21733    * This method is getter only.
21734    *
21735    * Return port of current url.
21736    *
21737    *
21738    * ```js
21739    * // given url http://example.com/#/some/path?foo=bar&baz=xoxo
21740    * var port = $location.port();
21741    * // => 80
21742    * ```
21743    *
21744    * @return {Number} port
21745    */
21746   port: locationGetter('$$port'),
21747
21748   /**
21749    * @ngdoc method
21750    * @name $location#path
21751    *
21752    * @description
21753    * This method is getter / setter.
21754    *
21755    * Return path of current url when called without any parameter.
21756    *
21757    * Change path when called with parameter and return `$location`.
21758    *
21759    * Note: Path should always begin with forward slash (/), this method will add the forward slash
21760    * if it is missing.
21761    *
21762    *
21763    * ```js
21764    * // given url http://example.com/#/some/path?foo=bar&baz=xoxo
21765    * var path = $location.path();
21766    * // => "/some/path"
21767    * ```
21768    *
21769    * @param {(string|number)=} path New path
21770    * @return {string} path
21771    */
21772   path: locationGetterSetter('$$path', function(path) {
21773     path = path !== null ? path.toString() : '';
21774     return path.charAt(0) == '/' ? path : '/' + path;
21775   }),
21776
21777   /**
21778    * @ngdoc method
21779    * @name $location#search
21780    *
21781    * @description
21782    * This method is getter / setter.
21783    *
21784    * Return search part (as object) of current url when called without any parameter.
21785    *
21786    * Change search part when called with parameter and return `$location`.
21787    *
21788    *
21789    * ```js
21790    * // given url http://example.com/#/some/path?foo=bar&baz=xoxo
21791    * var searchObject = $location.search();
21792    * // => {foo: 'bar', baz: 'xoxo'}
21793    *
21794    * // set foo to 'yipee'
21795    * $location.search('foo', 'yipee');
21796    * // $location.search() => {foo: 'yipee', baz: 'xoxo'}
21797    * ```
21798    *
21799    * @param {string|Object.<string>|Object.<Array.<string>>} search New search params - string or
21800    * hash object.
21801    *
21802    * When called with a single argument the method acts as a setter, setting the `search` component
21803    * of `$location` to the specified value.
21804    *
21805    * If the argument is a hash object containing an array of values, these values will be encoded
21806    * as duplicate search parameters in the url.
21807    *
21808    * @param {(string|Number|Array<string>|boolean)=} paramValue If `search` is a string or number, then `paramValue`
21809    * will override only a single search property.
21810    *
21811    * If `paramValue` is an array, it will override the property of the `search` component of
21812    * `$location` specified via the first argument.
21813    *
21814    * If `paramValue` is `null`, the property specified via the first argument will be deleted.
21815    *
21816    * If `paramValue` is `true`, the property specified via the first argument will be added with no
21817    * value nor trailing equal sign.
21818    *
21819    * @return {Object} If called with no arguments returns the parsed `search` object. If called with
21820    * one or more arguments returns `$location` object itself.
21821    */
21822   search: function(search, paramValue) {
21823     switch (arguments.length) {
21824       case 0:
21825         return this.$$search;
21826       case 1:
21827         if (isString(search) || isNumber(search)) {
21828           search = search.toString();
21829           this.$$search = parseKeyValue(search);
21830         } else if (isObject(search)) {
21831           search = copy(search, {});
21832           // remove object undefined or null properties
21833           forEach(search, function(value, key) {
21834             if (value == null) delete search[key];
21835           });
21836
21837           this.$$search = search;
21838         } else {
21839           throw $locationMinErr('isrcharg',
21840               'The first argument of the `$location#search()` call must be a string or an object.');
21841         }
21842         break;
21843       default:
21844         if (isUndefined(paramValue) || paramValue === null) {
21845           delete this.$$search[search];
21846         } else {
21847           this.$$search[search] = paramValue;
21848         }
21849     }
21850
21851     this.$$compose();
21852     return this;
21853   },
21854
21855   /**
21856    * @ngdoc method
21857    * @name $location#hash
21858    *
21859    * @description
21860    * This method is getter / setter.
21861    *
21862    * Returns the hash fragment when called without any parameters.
21863    *
21864    * Changes the hash fragment when called with a parameter and returns `$location`.
21865    *
21866    *
21867    * ```js
21868    * // given url http://example.com/#/some/path?foo=bar&baz=xoxo#hashValue
21869    * var hash = $location.hash();
21870    * // => "hashValue"
21871    * ```
21872    *
21873    * @param {(string|number)=} hash New hash fragment
21874    * @return {string} hash
21875    */
21876   hash: locationGetterSetter('$$hash', function(hash) {
21877     return hash !== null ? hash.toString() : '';
21878   }),
21879
21880   /**
21881    * @ngdoc method
21882    * @name $location#replace
21883    *
21884    * @description
21885    * If called, all changes to $location during the current `$digest` will replace the current history
21886    * record, instead of adding a new one.
21887    */
21888   replace: function() {
21889     this.$$replace = true;
21890     return this;
21891   }
21892 };
21893
21894 forEach([LocationHashbangInHtml5Url, LocationHashbangUrl, LocationHtml5Url], function(Location) {
21895   Location.prototype = Object.create(locationPrototype);
21896
21897   /**
21898    * @ngdoc method
21899    * @name $location#state
21900    *
21901    * @description
21902    * This method is getter / setter.
21903    *
21904    * Return the history state object when called without any parameter.
21905    *
21906    * Change the history state object when called with one parameter and return `$location`.
21907    * The state object is later passed to `pushState` or `replaceState`.
21908    *
21909    * NOTE: This method is supported only in HTML5 mode and only in browsers supporting
21910    * the HTML5 History API (i.e. methods `pushState` and `replaceState`). If you need to support
21911    * older browsers (like IE9 or Android < 4.0), don't use this method.
21912    *
21913    * @param {object=} state State object for pushState or replaceState
21914    * @return {object} state
21915    */
21916   Location.prototype.state = function(state) {
21917     if (!arguments.length) {
21918       return this.$$state;
21919     }
21920
21921     if (Location !== LocationHtml5Url || !this.$$html5) {
21922       throw $locationMinErr('nostate', 'History API state support is available only ' +
21923         'in HTML5 mode and only in browsers supporting HTML5 History API');
21924     }
21925     // The user might modify `stateObject` after invoking `$location.state(stateObject)`
21926     // but we're changing the $$state reference to $browser.state() during the $digest
21927     // so the modification window is narrow.
21928     this.$$state = isUndefined(state) ? null : state;
21929
21930     return this;
21931   };
21932 });
21933
21934
21935 function locationGetter(property) {
21936   return function() {
21937     return this[property];
21938   };
21939 }
21940
21941
21942 function locationGetterSetter(property, preprocess) {
21943   return function(value) {
21944     if (isUndefined(value)) {
21945       return this[property];
21946     }
21947
21948     this[property] = preprocess(value);
21949     this.$$compose();
21950
21951     return this;
21952   };
21953 }
21954
21955
21956 /**
21957  * @ngdoc service
21958  * @name $location
21959  *
21960  * @requires $rootElement
21961  *
21962  * @description
21963  * The $location service parses the URL in the browser address bar (based on the
21964  * [window.location](https://developer.mozilla.org/en/window.location)) and makes the URL
21965  * available to your application. Changes to the URL in the address bar are reflected into
21966  * $location service and changes to $location are reflected into the browser address bar.
21967  *
21968  * **The $location service:**
21969  *
21970  * - Exposes the current URL in the browser address bar, so you can
21971  *   - Watch and observe the URL.
21972  *   - Change the URL.
21973  * - Synchronizes the URL with the browser when the user
21974  *   - Changes the address bar.
21975  *   - Clicks the back or forward button (or clicks a History link).
21976  *   - Clicks on a link.
21977  * - Represents the URL object as a set of methods (protocol, host, port, path, search, hash).
21978  *
21979  * For more information see {@link guide/$location Developer Guide: Using $location}
21980  */
21981
21982 /**
21983  * @ngdoc provider
21984  * @name $locationProvider
21985  * @description
21986  * Use the `$locationProvider` to configure how the application deep linking paths are stored.
21987  */
21988 function $LocationProvider() {
21989   var hashPrefix = '',
21990       html5Mode = {
21991         enabled: false,
21992         requireBase: true,
21993         rewriteLinks: true
21994       };
21995
21996   /**
21997    * @ngdoc method
21998    * @name $locationProvider#hashPrefix
21999    * @description
22000    * @param {string=} prefix Prefix for hash part (containing path and search)
22001    * @returns {*} current value if used as getter or itself (chaining) if used as setter
22002    */
22003   this.hashPrefix = function(prefix) {
22004     if (isDefined(prefix)) {
22005       hashPrefix = prefix;
22006       return this;
22007     } else {
22008       return hashPrefix;
22009     }
22010   };
22011
22012   /**
22013    * @ngdoc method
22014    * @name $locationProvider#html5Mode
22015    * @description
22016    * @param {(boolean|Object)=} mode If boolean, sets `html5Mode.enabled` to value.
22017    *   If object, sets `enabled`, `requireBase` and `rewriteLinks` to respective values. Supported
22018    *   properties:
22019    *   - **enabled** – `{boolean}` – (default: false) If true, will rely on `history.pushState` to
22020    *     change urls where supported. Will fall back to hash-prefixed paths in browsers that do not
22021    *     support `pushState`.
22022    *   - **requireBase** - `{boolean}` - (default: `true`) When html5Mode is enabled, specifies
22023    *     whether or not a <base> tag is required to be present. If `enabled` and `requireBase` are
22024    *     true, and a base tag is not present, an error will be thrown when `$location` is injected.
22025    *     See the {@link guide/$location $location guide for more information}
22026    *   - **rewriteLinks** - `{boolean}` - (default: `true`) When html5Mode is enabled,
22027    *     enables/disables url rewriting for relative links.
22028    *
22029    * @returns {Object} html5Mode object if used as getter or itself (chaining) if used as setter
22030    */
22031   this.html5Mode = function(mode) {
22032     if (isBoolean(mode)) {
22033       html5Mode.enabled = mode;
22034       return this;
22035     } else if (isObject(mode)) {
22036
22037       if (isBoolean(mode.enabled)) {
22038         html5Mode.enabled = mode.enabled;
22039       }
22040
22041       if (isBoolean(mode.requireBase)) {
22042         html5Mode.requireBase = mode.requireBase;
22043       }
22044
22045       if (isBoolean(mode.rewriteLinks)) {
22046         html5Mode.rewriteLinks = mode.rewriteLinks;
22047       }
22048
22049       return this;
22050     } else {
22051       return html5Mode;
22052     }
22053   };
22054
22055   /**
22056    * @ngdoc event
22057    * @name $location#$locationChangeStart
22058    * @eventType broadcast on root scope
22059    * @description
22060    * Broadcasted before a URL will change.
22061    *
22062    * This change can be prevented by calling
22063    * `preventDefault` method of the event. See {@link ng.$rootScope.Scope#$on} for more
22064    * details about event object. Upon successful change
22065    * {@link ng.$location#$locationChangeSuccess $locationChangeSuccess} is fired.
22066    *
22067    * The `newState` and `oldState` parameters may be defined only in HTML5 mode and when
22068    * the browser supports the HTML5 History API.
22069    *
22070    * @param {Object} angularEvent Synthetic event object.
22071    * @param {string} newUrl New URL
22072    * @param {string=} oldUrl URL that was before it was changed.
22073    * @param {string=} newState New history state object
22074    * @param {string=} oldState History state object that was before it was changed.
22075    */
22076
22077   /**
22078    * @ngdoc event
22079    * @name $location#$locationChangeSuccess
22080    * @eventType broadcast on root scope
22081    * @description
22082    * Broadcasted after a URL was changed.
22083    *
22084    * The `newState` and `oldState` parameters may be defined only in HTML5 mode and when
22085    * the browser supports the HTML5 History API.
22086    *
22087    * @param {Object} angularEvent Synthetic event object.
22088    * @param {string} newUrl New URL
22089    * @param {string=} oldUrl URL that was before it was changed.
22090    * @param {string=} newState New history state object
22091    * @param {string=} oldState History state object that was before it was changed.
22092    */
22093
22094   this.$get = ['$rootScope', '$browser', '$sniffer', '$rootElement', '$window',
22095       function($rootScope, $browser, $sniffer, $rootElement, $window) {
22096     var $location,
22097         LocationMode,
22098         baseHref = $browser.baseHref(), // if base[href] is undefined, it defaults to ''
22099         initialUrl = $browser.url(),
22100         appBase;
22101
22102     if (html5Mode.enabled) {
22103       if (!baseHref && html5Mode.requireBase) {
22104         throw $locationMinErr('nobase',
22105           "$location in HTML5 mode requires a <base> tag to be present!");
22106       }
22107       appBase = serverBase(initialUrl) + (baseHref || '/');
22108       LocationMode = $sniffer.history ? LocationHtml5Url : LocationHashbangInHtml5Url;
22109     } else {
22110       appBase = stripHash(initialUrl);
22111       LocationMode = LocationHashbangUrl;
22112     }
22113     var appBaseNoFile = stripFile(appBase);
22114
22115     $location = new LocationMode(appBase, appBaseNoFile, '#' + hashPrefix);
22116     $location.$$parseLinkUrl(initialUrl, initialUrl);
22117
22118     $location.$$state = $browser.state();
22119
22120     var IGNORE_URI_REGEXP = /^\s*(javascript|mailto):/i;
22121
22122     function setBrowserUrlWithFallback(url, replace, state) {
22123       var oldUrl = $location.url();
22124       var oldState = $location.$$state;
22125       try {
22126         $browser.url(url, replace, state);
22127
22128         // Make sure $location.state() returns referentially identical (not just deeply equal)
22129         // state object; this makes possible quick checking if the state changed in the digest
22130         // loop. Checking deep equality would be too expensive.
22131         $location.$$state = $browser.state();
22132       } catch (e) {
22133         // Restore old values if pushState fails
22134         $location.url(oldUrl);
22135         $location.$$state = oldState;
22136
22137         throw e;
22138       }
22139     }
22140
22141     $rootElement.on('click', function(event) {
22142       // TODO(vojta): rewrite link when opening in new tab/window (in legacy browser)
22143       // currently we open nice url link and redirect then
22144
22145       if (!html5Mode.rewriteLinks || event.ctrlKey || event.metaKey || event.shiftKey || event.which == 2 || event.button == 2) return;
22146
22147       var elm = jqLite(event.target);
22148
22149       // traverse the DOM up to find first A tag
22150       while (nodeName_(elm[0]) !== 'a') {
22151         // ignore rewriting if no A tag (reached root element, or no parent - removed from document)
22152         if (elm[0] === $rootElement[0] || !(elm = elm.parent())[0]) return;
22153       }
22154
22155       var absHref = elm.prop('href');
22156       // get the actual href attribute - see
22157       // http://msdn.microsoft.com/en-us/library/ie/dd347148(v=vs.85).aspx
22158       var relHref = elm.attr('href') || elm.attr('xlink:href');
22159
22160       if (isObject(absHref) && absHref.toString() === '[object SVGAnimatedString]') {
22161         // SVGAnimatedString.animVal should be identical to SVGAnimatedString.baseVal, unless during
22162         // an animation.
22163         absHref = urlResolve(absHref.animVal).href;
22164       }
22165
22166       // Ignore when url is started with javascript: or mailto:
22167       if (IGNORE_URI_REGEXP.test(absHref)) return;
22168
22169       if (absHref && !elm.attr('target') && !event.isDefaultPrevented()) {
22170         if ($location.$$parseLinkUrl(absHref, relHref)) {
22171           // We do a preventDefault for all urls that are part of the angular application,
22172           // in html5mode and also without, so that we are able to abort navigation without
22173           // getting double entries in the location history.
22174           event.preventDefault();
22175           // update location manually
22176           if ($location.absUrl() != $browser.url()) {
22177             $rootScope.$apply();
22178             // hack to work around FF6 bug 684208 when scenario runner clicks on links
22179             $window.angular['ff-684208-preventDefault'] = true;
22180           }
22181         }
22182       }
22183     });
22184
22185
22186     // rewrite hashbang url <> html5 url
22187     if (trimEmptyHash($location.absUrl()) != trimEmptyHash(initialUrl)) {
22188       $browser.url($location.absUrl(), true);
22189     }
22190
22191     var initializing = true;
22192
22193     // update $location when $browser url changes
22194     $browser.onUrlChange(function(newUrl, newState) {
22195
22196       if (isUndefined(beginsWith(appBaseNoFile, newUrl))) {
22197         // If we are navigating outside of the app then force a reload
22198         $window.location.href = newUrl;
22199         return;
22200       }
22201
22202       $rootScope.$evalAsync(function() {
22203         var oldUrl = $location.absUrl();
22204         var oldState = $location.$$state;
22205         var defaultPrevented;
22206         newUrl = trimEmptyHash(newUrl);
22207         $location.$$parse(newUrl);
22208         $location.$$state = newState;
22209
22210         defaultPrevented = $rootScope.$broadcast('$locationChangeStart', newUrl, oldUrl,
22211             newState, oldState).defaultPrevented;
22212
22213         // if the location was changed by a `$locationChangeStart` handler then stop
22214         // processing this location change
22215         if ($location.absUrl() !== newUrl) return;
22216
22217         if (defaultPrevented) {
22218           $location.$$parse(oldUrl);
22219           $location.$$state = oldState;
22220           setBrowserUrlWithFallback(oldUrl, false, oldState);
22221         } else {
22222           initializing = false;
22223           afterLocationChange(oldUrl, oldState);
22224         }
22225       });
22226       if (!$rootScope.$$phase) $rootScope.$digest();
22227     });
22228
22229     // update browser
22230     $rootScope.$watch(function $locationWatch() {
22231       var oldUrl = trimEmptyHash($browser.url());
22232       var newUrl = trimEmptyHash($location.absUrl());
22233       var oldState = $browser.state();
22234       var currentReplace = $location.$$replace;
22235       var urlOrStateChanged = oldUrl !== newUrl ||
22236         ($location.$$html5 && $sniffer.history && oldState !== $location.$$state);
22237
22238       if (initializing || urlOrStateChanged) {
22239         initializing = false;
22240
22241         $rootScope.$evalAsync(function() {
22242           var newUrl = $location.absUrl();
22243           var defaultPrevented = $rootScope.$broadcast('$locationChangeStart', newUrl, oldUrl,
22244               $location.$$state, oldState).defaultPrevented;
22245
22246           // if the location was changed by a `$locationChangeStart` handler then stop
22247           // processing this location change
22248           if ($location.absUrl() !== newUrl) return;
22249
22250           if (defaultPrevented) {
22251             $location.$$parse(oldUrl);
22252             $location.$$state = oldState;
22253           } else {
22254             if (urlOrStateChanged) {
22255               setBrowserUrlWithFallback(newUrl, currentReplace,
22256                                         oldState === $location.$$state ? null : $location.$$state);
22257             }
22258             afterLocationChange(oldUrl, oldState);
22259           }
22260         });
22261       }
22262
22263       $location.$$replace = false;
22264
22265       // we don't need to return anything because $evalAsync will make the digest loop dirty when
22266       // there is a change
22267     });
22268
22269     return $location;
22270
22271     function afterLocationChange(oldUrl, oldState) {
22272       $rootScope.$broadcast('$locationChangeSuccess', $location.absUrl(), oldUrl,
22273         $location.$$state, oldState);
22274     }
22275 }];
22276 }
22277
22278 /**
22279  * @ngdoc service
22280  * @name $log
22281  * @requires $window
22282  *
22283  * @description
22284  * Simple service for logging. Default implementation safely writes the message
22285  * into the browser's console (if present).
22286  *
22287  * The main purpose of this service is to simplify debugging and troubleshooting.
22288  *
22289  * The default is to log `debug` messages. You can use
22290  * {@link ng.$logProvider ng.$logProvider#debugEnabled} to change this.
22291  *
22292  * @example
22293    <example module="logExample">
22294      <file name="script.js">
22295        angular.module('logExample', [])
22296          .controller('LogController', ['$scope', '$log', function($scope, $log) {
22297            $scope.$log = $log;
22298            $scope.message = 'Hello World!';
22299          }]);
22300      </file>
22301      <file name="index.html">
22302        <div ng-controller="LogController">
22303          <p>Reload this page with open console, enter text and hit the log button...</p>
22304          <label>Message:
22305          <input type="text" ng-model="message" /></label>
22306          <button ng-click="$log.log(message)">log</button>
22307          <button ng-click="$log.warn(message)">warn</button>
22308          <button ng-click="$log.info(message)">info</button>
22309          <button ng-click="$log.error(message)">error</button>
22310          <button ng-click="$log.debug(message)">debug</button>
22311        </div>
22312      </file>
22313    </example>
22314  */
22315
22316 /**
22317  * @ngdoc provider
22318  * @name $logProvider
22319  * @description
22320  * Use the `$logProvider` to configure how the application logs messages
22321  */
22322 function $LogProvider() {
22323   var debug = true,
22324       self = this;
22325
22326   /**
22327    * @ngdoc method
22328    * @name $logProvider#debugEnabled
22329    * @description
22330    * @param {boolean=} flag enable or disable debug level messages
22331    * @returns {*} current value if used as getter or itself (chaining) if used as setter
22332    */
22333   this.debugEnabled = function(flag) {
22334     if (isDefined(flag)) {
22335       debug = flag;
22336     return this;
22337     } else {
22338       return debug;
22339     }
22340   };
22341
22342   this.$get = ['$window', function($window) {
22343     return {
22344       /**
22345        * @ngdoc method
22346        * @name $log#log
22347        *
22348        * @description
22349        * Write a log message
22350        */
22351       log: consoleLog('log'),
22352
22353       /**
22354        * @ngdoc method
22355        * @name $log#info
22356        *
22357        * @description
22358        * Write an information message
22359        */
22360       info: consoleLog('info'),
22361
22362       /**
22363        * @ngdoc method
22364        * @name $log#warn
22365        *
22366        * @description
22367        * Write a warning message
22368        */
22369       warn: consoleLog('warn'),
22370
22371       /**
22372        * @ngdoc method
22373        * @name $log#error
22374        *
22375        * @description
22376        * Write an error message
22377        */
22378       error: consoleLog('error'),
22379
22380       /**
22381        * @ngdoc method
22382        * @name $log#debug
22383        *
22384        * @description
22385        * Write a debug message
22386        */
22387       debug: (function() {
22388         var fn = consoleLog('debug');
22389
22390         return function() {
22391           if (debug) {
22392             fn.apply(self, arguments);
22393           }
22394         };
22395       }())
22396     };
22397
22398     function formatError(arg) {
22399       if (arg instanceof Error) {
22400         if (arg.stack) {
22401           arg = (arg.message && arg.stack.indexOf(arg.message) === -1)
22402               ? 'Error: ' + arg.message + '\n' + arg.stack
22403               : arg.stack;
22404         } else if (arg.sourceURL) {
22405           arg = arg.message + '\n' + arg.sourceURL + ':' + arg.line;
22406         }
22407       }
22408       return arg;
22409     }
22410
22411     function consoleLog(type) {
22412       var console = $window.console || {},
22413           logFn = console[type] || console.log || noop,
22414           hasApply = false;
22415
22416       // Note: reading logFn.apply throws an error in IE11 in IE8 document mode.
22417       // The reason behind this is that console.log has type "object" in IE8...
22418       try {
22419         hasApply = !!logFn.apply;
22420       } catch (e) {}
22421
22422       if (hasApply) {
22423         return function() {
22424           var args = [];
22425           forEach(arguments, function(arg) {
22426             args.push(formatError(arg));
22427           });
22428           return logFn.apply(console, args);
22429         };
22430       }
22431
22432       // we are IE which either doesn't have window.console => this is noop and we do nothing,
22433       // or we are IE where console.log doesn't have apply so we log at least first 2 args
22434       return function(arg1, arg2) {
22435         logFn(arg1, arg2 == null ? '' : arg2);
22436       };
22437     }
22438   }];
22439 }
22440
22441 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
22442  *     Any commits to this file should be reviewed with security in mind.  *
22443  *   Changes to this file can potentially create security vulnerabilities. *
22444  *          An approval from 2 Core members with history of modifying      *
22445  *                         this file is required.                          *
22446  *                                                                         *
22447  *  Does the change somehow allow for arbitrary javascript to be executed? *
22448  *    Or allows for someone to change the prototype of built-in objects?   *
22449  *     Or gives undesired access to variables likes document or window?    *
22450  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
22451
22452 var $parseMinErr = minErr('$parse');
22453
22454 // Sandboxing Angular Expressions
22455 // ------------------------------
22456 // Angular expressions are generally considered safe because these expressions only have direct
22457 // access to `$scope` and locals. However, one can obtain the ability to execute arbitrary JS code by
22458 // obtaining a reference to native JS functions such as the Function constructor.
22459 //
22460 // As an example, consider the following Angular expression:
22461 //
22462 //   {}.toString.constructor('alert("evil JS code")')
22463 //
22464 // This sandboxing technique is not perfect and doesn't aim to be. The goal is to prevent exploits
22465 // against the expression language, but not to prevent exploits that were enabled by exposing
22466 // sensitive JavaScript or browser APIs on Scope. Exposing such objects on a Scope is never a good
22467 // practice and therefore we are not even trying to protect against interaction with an object
22468 // explicitly exposed in this way.
22469 //
22470 // In general, it is not possible to access a Window object from an angular expression unless a
22471 // window or some DOM object that has a reference to window is published onto a Scope.
22472 // Similarly we prevent invocations of function known to be dangerous, as well as assignments to
22473 // native objects.
22474 //
22475 // See https://docs.angularjs.org/guide/security
22476
22477
22478 function ensureSafeMemberName(name, fullExpression) {
22479   if (name === "__defineGetter__" || name === "__defineSetter__"
22480       || name === "__lookupGetter__" || name === "__lookupSetter__"
22481       || name === "__proto__") {
22482     throw $parseMinErr('isecfld',
22483         'Attempting to access a disallowed field in Angular expressions! '
22484         + 'Expression: {0}', fullExpression);
22485   }
22486   return name;
22487 }
22488
22489 function getStringValue(name) {
22490   // Property names must be strings. This means that non-string objects cannot be used
22491   // as keys in an object. Any non-string object, including a number, is typecasted
22492   // into a string via the toString method.
22493   // -- MDN, https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Operators/Property_accessors#Property_names
22494   //
22495   // So, to ensure that we are checking the same `name` that JavaScript would use, we cast it
22496   // to a string. It's not always possible. If `name` is an object and its `toString` method is
22497   // 'broken' (doesn't return a string, isn't a function, etc.), an error will be thrown:
22498   //
22499   // TypeError: Cannot convert object to primitive value
22500   //
22501   // For performance reasons, we don't catch this error here and allow it to propagate up the call
22502   // stack. Note that you'll get the same error in JavaScript if you try to access a property using
22503   // such a 'broken' object as a key.
22504   return name + '';
22505 }
22506
22507 function ensureSafeObject(obj, fullExpression) {
22508   // nifty check if obj is Function that is fast and works across iframes and other contexts
22509   if (obj) {
22510     if (obj.constructor === obj) {
22511       throw $parseMinErr('isecfn',
22512           'Referencing Function in Angular expressions is disallowed! Expression: {0}',
22513           fullExpression);
22514     } else if (// isWindow(obj)
22515         obj.window === obj) {
22516       throw $parseMinErr('isecwindow',
22517           'Referencing the Window in Angular expressions is disallowed! Expression: {0}',
22518           fullExpression);
22519     } else if (// isElement(obj)
22520         obj.children && (obj.nodeName || (obj.prop && obj.attr && obj.find))) {
22521       throw $parseMinErr('isecdom',
22522           'Referencing DOM nodes in Angular expressions is disallowed! Expression: {0}',
22523           fullExpression);
22524     } else if (// block Object so that we can't get hold of dangerous Object.* methods
22525         obj === Object) {
22526       throw $parseMinErr('isecobj',
22527           'Referencing Object in Angular expressions is disallowed! Expression: {0}',
22528           fullExpression);
22529     }
22530   }
22531   return obj;
22532 }
22533
22534 var CALL = Function.prototype.call;
22535 var APPLY = Function.prototype.apply;
22536 var BIND = Function.prototype.bind;
22537
22538 function ensureSafeFunction(obj, fullExpression) {
22539   if (obj) {
22540     if (obj.constructor === obj) {
22541       throw $parseMinErr('isecfn',
22542         'Referencing Function in Angular expressions is disallowed! Expression: {0}',
22543         fullExpression);
22544     } else if (obj === CALL || obj === APPLY || obj === BIND) {
22545       throw $parseMinErr('isecff',
22546         'Referencing call, apply or bind in Angular expressions is disallowed! Expression: {0}',
22547         fullExpression);
22548     }
22549   }
22550 }
22551
22552 function ensureSafeAssignContext(obj, fullExpression) {
22553   if (obj) {
22554     if (obj === (0).constructor || obj === (false).constructor || obj === ''.constructor ||
22555         obj === {}.constructor || obj === [].constructor || obj === Function.constructor) {
22556       throw $parseMinErr('isecaf',
22557         'Assigning to a constructor is disallowed! Expression: {0}', fullExpression);
22558     }
22559   }
22560 }
22561
22562 var OPERATORS = createMap();
22563 forEach('+ - * / % === !== == != < > <= >= && || ! = |'.split(' '), function(operator) { OPERATORS[operator] = true; });
22564 var ESCAPE = {"n":"\n", "f":"\f", "r":"\r", "t":"\t", "v":"\v", "'":"'", '"':'"'};
22565
22566
22567 /////////////////////////////////////////
22568
22569
22570 /**
22571  * @constructor
22572  */
22573 var Lexer = function(options) {
22574   this.options = options;
22575 };
22576
22577 Lexer.prototype = {
22578   constructor: Lexer,
22579
22580   lex: function(text) {
22581     this.text = text;
22582     this.index = 0;
22583     this.tokens = [];
22584
22585     while (this.index < this.text.length) {
22586       var ch = this.text.charAt(this.index);
22587       if (ch === '"' || ch === "'") {
22588         this.readString(ch);
22589       } else if (this.isNumber(ch) || ch === '.' && this.isNumber(this.peek())) {
22590         this.readNumber();
22591       } else if (this.isIdent(ch)) {
22592         this.readIdent();
22593       } else if (this.is(ch, '(){}[].,;:?')) {
22594         this.tokens.push({index: this.index, text: ch});
22595         this.index++;
22596       } else if (this.isWhitespace(ch)) {
22597         this.index++;
22598       } else {
22599         var ch2 = ch + this.peek();
22600         var ch3 = ch2 + this.peek(2);
22601         var op1 = OPERATORS[ch];
22602         var op2 = OPERATORS[ch2];
22603         var op3 = OPERATORS[ch3];
22604         if (op1 || op2 || op3) {
22605           var token = op3 ? ch3 : (op2 ? ch2 : ch);
22606           this.tokens.push({index: this.index, text: token, operator: true});
22607           this.index += token.length;
22608         } else {
22609           this.throwError('Unexpected next character ', this.index, this.index + 1);
22610         }
22611       }
22612     }
22613     return this.tokens;
22614   },
22615
22616   is: function(ch, chars) {
22617     return chars.indexOf(ch) !== -1;
22618   },
22619
22620   peek: function(i) {
22621     var num = i || 1;
22622     return (this.index + num < this.text.length) ? this.text.charAt(this.index + num) : false;
22623   },
22624
22625   isNumber: function(ch) {
22626     return ('0' <= ch && ch <= '9') && typeof ch === "string";
22627   },
22628
22629   isWhitespace: function(ch) {
22630     // IE treats non-breaking space as \u00A0
22631     return (ch === ' ' || ch === '\r' || ch === '\t' ||
22632             ch === '\n' || ch === '\v' || ch === '\u00A0');
22633   },
22634
22635   isIdent: function(ch) {
22636     return ('a' <= ch && ch <= 'z' ||
22637             'A' <= ch && ch <= 'Z' ||
22638             '_' === ch || ch === '$');
22639   },
22640
22641   isExpOperator: function(ch) {
22642     return (ch === '-' || ch === '+' || this.isNumber(ch));
22643   },
22644
22645   throwError: function(error, start, end) {
22646     end = end || this.index;
22647     var colStr = (isDefined(start)
22648             ? 's ' + start +  '-' + this.index + ' [' + this.text.substring(start, end) + ']'
22649             : ' ' + end);
22650     throw $parseMinErr('lexerr', 'Lexer Error: {0} at column{1} in expression [{2}].',
22651         error, colStr, this.text);
22652   },
22653
22654   readNumber: function() {
22655     var number = '';
22656     var start = this.index;
22657     while (this.index < this.text.length) {
22658       var ch = lowercase(this.text.charAt(this.index));
22659       if (ch == '.' || this.isNumber(ch)) {
22660         number += ch;
22661       } else {
22662         var peekCh = this.peek();
22663         if (ch == 'e' && this.isExpOperator(peekCh)) {
22664           number += ch;
22665         } else if (this.isExpOperator(ch) &&
22666             peekCh && this.isNumber(peekCh) &&
22667             number.charAt(number.length - 1) == 'e') {
22668           number += ch;
22669         } else if (this.isExpOperator(ch) &&
22670             (!peekCh || !this.isNumber(peekCh)) &&
22671             number.charAt(number.length - 1) == 'e') {
22672           this.throwError('Invalid exponent');
22673         } else {
22674           break;
22675         }
22676       }
22677       this.index++;
22678     }
22679     this.tokens.push({
22680       index: start,
22681       text: number,
22682       constant: true,
22683       value: Number(number)
22684     });
22685   },
22686
22687   readIdent: function() {
22688     var start = this.index;
22689     while (this.index < this.text.length) {
22690       var ch = this.text.charAt(this.index);
22691       if (!(this.isIdent(ch) || this.isNumber(ch))) {
22692         break;
22693       }
22694       this.index++;
22695     }
22696     this.tokens.push({
22697       index: start,
22698       text: this.text.slice(start, this.index),
22699       identifier: true
22700     });
22701   },
22702
22703   readString: function(quote) {
22704     var start = this.index;
22705     this.index++;
22706     var string = '';
22707     var rawString = quote;
22708     var escape = false;
22709     while (this.index < this.text.length) {
22710       var ch = this.text.charAt(this.index);
22711       rawString += ch;
22712       if (escape) {
22713         if (ch === 'u') {
22714           var hex = this.text.substring(this.index + 1, this.index + 5);
22715           if (!hex.match(/[\da-f]{4}/i)) {
22716             this.throwError('Invalid unicode escape [\\u' + hex + ']');
22717           }
22718           this.index += 4;
22719           string += String.fromCharCode(parseInt(hex, 16));
22720         } else {
22721           var rep = ESCAPE[ch];
22722           string = string + (rep || ch);
22723         }
22724         escape = false;
22725       } else if (ch === '\\') {
22726         escape = true;
22727       } else if (ch === quote) {
22728         this.index++;
22729         this.tokens.push({
22730           index: start,
22731           text: rawString,
22732           constant: true,
22733           value: string
22734         });
22735         return;
22736       } else {
22737         string += ch;
22738       }
22739       this.index++;
22740     }
22741     this.throwError('Unterminated quote', start);
22742   }
22743 };
22744
22745 var AST = function(lexer, options) {
22746   this.lexer = lexer;
22747   this.options = options;
22748 };
22749
22750 AST.Program = 'Program';
22751 AST.ExpressionStatement = 'ExpressionStatement';
22752 AST.AssignmentExpression = 'AssignmentExpression';
22753 AST.ConditionalExpression = 'ConditionalExpression';
22754 AST.LogicalExpression = 'LogicalExpression';
22755 AST.BinaryExpression = 'BinaryExpression';
22756 AST.UnaryExpression = 'UnaryExpression';
22757 AST.CallExpression = 'CallExpression';
22758 AST.MemberExpression = 'MemberExpression';
22759 AST.Identifier = 'Identifier';
22760 AST.Literal = 'Literal';
22761 AST.ArrayExpression = 'ArrayExpression';
22762 AST.Property = 'Property';
22763 AST.ObjectExpression = 'ObjectExpression';
22764 AST.ThisExpression = 'ThisExpression';
22765 AST.LocalsExpression = 'LocalsExpression';
22766
22767 // Internal use only
22768 AST.NGValueParameter = 'NGValueParameter';
22769
22770 AST.prototype = {
22771   ast: function(text) {
22772     this.text = text;
22773     this.tokens = this.lexer.lex(text);
22774
22775     var value = this.program();
22776
22777     if (this.tokens.length !== 0) {
22778       this.throwError('is an unexpected token', this.tokens[0]);
22779     }
22780
22781     return value;
22782   },
22783
22784   program: function() {
22785     var body = [];
22786     while (true) {
22787       if (this.tokens.length > 0 && !this.peek('}', ')', ';', ']'))
22788         body.push(this.expressionStatement());
22789       if (!this.expect(';')) {
22790         return { type: AST.Program, body: body};
22791       }
22792     }
22793   },
22794
22795   expressionStatement: function() {
22796     return { type: AST.ExpressionStatement, expression: this.filterChain() };
22797   },
22798
22799   filterChain: function() {
22800     var left = this.expression();
22801     var token;
22802     while ((token = this.expect('|'))) {
22803       left = this.filter(left);
22804     }
22805     return left;
22806   },
22807
22808   expression: function() {
22809     return this.assignment();
22810   },
22811
22812   assignment: function() {
22813     var result = this.ternary();
22814     if (this.expect('=')) {
22815       result = { type: AST.AssignmentExpression, left: result, right: this.assignment(), operator: '='};
22816     }
22817     return result;
22818   },
22819
22820   ternary: function() {
22821     var test = this.logicalOR();
22822     var alternate;
22823     var consequent;
22824     if (this.expect('?')) {
22825       alternate = this.expression();
22826       if (this.consume(':')) {
22827         consequent = this.expression();
22828         return { type: AST.ConditionalExpression, test: test, alternate: alternate, consequent: consequent};
22829       }
22830     }
22831     return test;
22832   },
22833
22834   logicalOR: function() {
22835     var left = this.logicalAND();
22836     while (this.expect('||')) {
22837       left = { type: AST.LogicalExpression, operator: '||', left: left, right: this.logicalAND() };
22838     }
22839     return left;
22840   },
22841
22842   logicalAND: function() {
22843     var left = this.equality();
22844     while (this.expect('&&')) {
22845       left = { type: AST.LogicalExpression, operator: '&&', left: left, right: this.equality()};
22846     }
22847     return left;
22848   },
22849
22850   equality: function() {
22851     var left = this.relational();
22852     var token;
22853     while ((token = this.expect('==','!=','===','!=='))) {
22854       left = { type: AST.BinaryExpression, operator: token.text, left: left, right: this.relational() };
22855     }
22856     return left;
22857   },
22858
22859   relational: function() {
22860     var left = this.additive();
22861     var token;
22862     while ((token = this.expect('<', '>', '<=', '>='))) {
22863       left = { type: AST.BinaryExpression, operator: token.text, left: left, right: this.additive() };
22864     }
22865     return left;
22866   },
22867
22868   additive: function() {
22869     var left = this.multiplicative();
22870     var token;
22871     while ((token = this.expect('+','-'))) {
22872       left = { type: AST.BinaryExpression, operator: token.text, left: left, right: this.multiplicative() };
22873     }
22874     return left;
22875   },
22876
22877   multiplicative: function() {
22878     var left = this.unary();
22879     var token;
22880     while ((token = this.expect('*','/','%'))) {
22881       left = { type: AST.BinaryExpression, operator: token.text, left: left, right: this.unary() };
22882     }
22883     return left;
22884   },
22885
22886   unary: function() {
22887     var token;
22888     if ((token = this.expect('+', '-', '!'))) {
22889       return { type: AST.UnaryExpression, operator: token.text, prefix: true, argument: this.unary() };
22890     } else {
22891       return this.primary();
22892     }
22893   },
22894
22895   primary: function() {
22896     var primary;
22897     if (this.expect('(')) {
22898       primary = this.filterChain();
22899       this.consume(')');
22900     } else if (this.expect('[')) {
22901       primary = this.arrayDeclaration();
22902     } else if (this.expect('{')) {
22903       primary = this.object();
22904     } else if (this.constants.hasOwnProperty(this.peek().text)) {
22905       primary = copy(this.constants[this.consume().text]);
22906     } else if (this.peek().identifier) {
22907       primary = this.identifier();
22908     } else if (this.peek().constant) {
22909       primary = this.constant();
22910     } else {
22911       this.throwError('not a primary expression', this.peek());
22912     }
22913
22914     var next;
22915     while ((next = this.expect('(', '[', '.'))) {
22916       if (next.text === '(') {
22917         primary = {type: AST.CallExpression, callee: primary, arguments: this.parseArguments() };
22918         this.consume(')');
22919       } else if (next.text === '[') {
22920         primary = { type: AST.MemberExpression, object: primary, property: this.expression(), computed: true };
22921         this.consume(']');
22922       } else if (next.text === '.') {
22923         primary = { type: AST.MemberExpression, object: primary, property: this.identifier(), computed: false };
22924       } else {
22925         this.throwError('IMPOSSIBLE');
22926       }
22927     }
22928     return primary;
22929   },
22930
22931   filter: function(baseExpression) {
22932     var args = [baseExpression];
22933     var result = {type: AST.CallExpression, callee: this.identifier(), arguments: args, filter: true};
22934
22935     while (this.expect(':')) {
22936       args.push(this.expression());
22937     }
22938
22939     return result;
22940   },
22941
22942   parseArguments: function() {
22943     var args = [];
22944     if (this.peekToken().text !== ')') {
22945       do {
22946         args.push(this.expression());
22947       } while (this.expect(','));
22948     }
22949     return args;
22950   },
22951
22952   identifier: function() {
22953     var token = this.consume();
22954     if (!token.identifier) {
22955       this.throwError('is not a valid identifier', token);
22956     }
22957     return { type: AST.Identifier, name: token.text };
22958   },
22959
22960   constant: function() {
22961     // TODO check that it is a constant
22962     return { type: AST.Literal, value: this.consume().value };
22963   },
22964
22965   arrayDeclaration: function() {
22966     var elements = [];
22967     if (this.peekToken().text !== ']') {
22968       do {
22969         if (this.peek(']')) {
22970           // Support trailing commas per ES5.1.
22971           break;
22972         }
22973         elements.push(this.expression());
22974       } while (this.expect(','));
22975     }
22976     this.consume(']');
22977
22978     return { type: AST.ArrayExpression, elements: elements };
22979   },
22980
22981   object: function() {
22982     var properties = [], property;
22983     if (this.peekToken().text !== '}') {
22984       do {
22985         if (this.peek('}')) {
22986           // Support trailing commas per ES5.1.
22987           break;
22988         }
22989         property = {type: AST.Property, kind: 'init'};
22990         if (this.peek().constant) {
22991           property.key = this.constant();
22992         } else if (this.peek().identifier) {
22993           property.key = this.identifier();
22994         } else {
22995           this.throwError("invalid key", this.peek());
22996         }
22997         this.consume(':');
22998         property.value = this.expression();
22999         properties.push(property);
23000       } while (this.expect(','));
23001     }
23002     this.consume('}');
23003
23004     return {type: AST.ObjectExpression, properties: properties };
23005   },
23006
23007   throwError: function(msg, token) {
23008     throw $parseMinErr('syntax',
23009         'Syntax Error: Token \'{0}\' {1} at column {2} of the expression [{3}] starting at [{4}].',
23010           token.text, msg, (token.index + 1), this.text, this.text.substring(token.index));
23011   },
23012
23013   consume: function(e1) {
23014     if (this.tokens.length === 0) {
23015       throw $parseMinErr('ueoe', 'Unexpected end of expression: {0}', this.text);
23016     }
23017
23018     var token = this.expect(e1);
23019     if (!token) {
23020       this.throwError('is unexpected, expecting [' + e1 + ']', this.peek());
23021     }
23022     return token;
23023   },
23024
23025   peekToken: function() {
23026     if (this.tokens.length === 0) {
23027       throw $parseMinErr('ueoe', 'Unexpected end of expression: {0}', this.text);
23028     }
23029     return this.tokens[0];
23030   },
23031
23032   peek: function(e1, e2, e3, e4) {
23033     return this.peekAhead(0, e1, e2, e3, e4);
23034   },
23035
23036   peekAhead: function(i, e1, e2, e3, e4) {
23037     if (this.tokens.length > i) {
23038       var token = this.tokens[i];
23039       var t = token.text;
23040       if (t === e1 || t === e2 || t === e3 || t === e4 ||
23041           (!e1 && !e2 && !e3 && !e4)) {
23042         return token;
23043       }
23044     }
23045     return false;
23046   },
23047
23048   expect: function(e1, e2, e3, e4) {
23049     var token = this.peek(e1, e2, e3, e4);
23050     if (token) {
23051       this.tokens.shift();
23052       return token;
23053     }
23054     return false;
23055   },
23056
23057
23058   /* `undefined` is not a constant, it is an identifier,
23059    * but using it as an identifier is not supported
23060    */
23061   constants: {
23062     'true': { type: AST.Literal, value: true },
23063     'false': { type: AST.Literal, value: false },
23064     'null': { type: AST.Literal, value: null },
23065     'undefined': {type: AST.Literal, value: undefined },
23066     'this': {type: AST.ThisExpression },
23067     '$locals': {type: AST.LocalsExpression }
23068   }
23069 };
23070
23071 function ifDefined(v, d) {
23072   return typeof v !== 'undefined' ? v : d;
23073 }
23074
23075 function plusFn(l, r) {
23076   if (typeof l === 'undefined') return r;
23077   if (typeof r === 'undefined') return l;
23078   return l + r;
23079 }
23080
23081 function isStateless($filter, filterName) {
23082   var fn = $filter(filterName);
23083   return !fn.$stateful;
23084 }
23085
23086 function findConstantAndWatchExpressions(ast, $filter) {
23087   var allConstants;
23088   var argsToWatch;
23089   switch (ast.type) {
23090   case AST.Program:
23091     allConstants = true;
23092     forEach(ast.body, function(expr) {
23093       findConstantAndWatchExpressions(expr.expression, $filter);
23094       allConstants = allConstants && expr.expression.constant;
23095     });
23096     ast.constant = allConstants;
23097     break;
23098   case AST.Literal:
23099     ast.constant = true;
23100     ast.toWatch = [];
23101     break;
23102   case AST.UnaryExpression:
23103     findConstantAndWatchExpressions(ast.argument, $filter);
23104     ast.constant = ast.argument.constant;
23105     ast.toWatch = ast.argument.toWatch;
23106     break;
23107   case AST.BinaryExpression:
23108     findConstantAndWatchExpressions(ast.left, $filter);
23109     findConstantAndWatchExpressions(ast.right, $filter);
23110     ast.constant = ast.left.constant && ast.right.constant;
23111     ast.toWatch = ast.left.toWatch.concat(ast.right.toWatch);
23112     break;
23113   case AST.LogicalExpression:
23114     findConstantAndWatchExpressions(ast.left, $filter);
23115     findConstantAndWatchExpressions(ast.right, $filter);
23116     ast.constant = ast.left.constant && ast.right.constant;
23117     ast.toWatch = ast.constant ? [] : [ast];
23118     break;
23119   case AST.ConditionalExpression:
23120     findConstantAndWatchExpressions(ast.test, $filter);
23121     findConstantAndWatchExpressions(ast.alternate, $filter);
23122     findConstantAndWatchExpressions(ast.consequent, $filter);
23123     ast.constant = ast.test.constant && ast.alternate.constant && ast.consequent.constant;
23124     ast.toWatch = ast.constant ? [] : [ast];
23125     break;
23126   case AST.Identifier:
23127     ast.constant = false;
23128     ast.toWatch = [ast];
23129     break;
23130   case AST.MemberExpression:
23131     findConstantAndWatchExpressions(ast.object, $filter);
23132     if (ast.computed) {
23133       findConstantAndWatchExpressions(ast.property, $filter);
23134     }
23135     ast.constant = ast.object.constant && (!ast.computed || ast.property.constant);
23136     ast.toWatch = [ast];
23137     break;
23138   case AST.CallExpression:
23139     allConstants = ast.filter ? isStateless($filter, ast.callee.name) : false;
23140     argsToWatch = [];
23141     forEach(ast.arguments, function(expr) {
23142       findConstantAndWatchExpressions(expr, $filter);
23143       allConstants = allConstants && expr.constant;
23144       if (!expr.constant) {
23145         argsToWatch.push.apply(argsToWatch, expr.toWatch);
23146       }
23147     });
23148     ast.constant = allConstants;
23149     ast.toWatch = ast.filter && isStateless($filter, ast.callee.name) ? argsToWatch : [ast];
23150     break;
23151   case AST.AssignmentExpression:
23152     findConstantAndWatchExpressions(ast.left, $filter);
23153     findConstantAndWatchExpressions(ast.right, $filter);
23154     ast.constant = ast.left.constant && ast.right.constant;
23155     ast.toWatch = [ast];
23156     break;
23157   case AST.ArrayExpression:
23158     allConstants = true;
23159     argsToWatch = [];
23160     forEach(ast.elements, function(expr) {
23161       findConstantAndWatchExpressions(expr, $filter);
23162       allConstants = allConstants && expr.constant;
23163       if (!expr.constant) {
23164         argsToWatch.push.apply(argsToWatch, expr.toWatch);
23165       }
23166     });
23167     ast.constant = allConstants;
23168     ast.toWatch = argsToWatch;
23169     break;
23170   case AST.ObjectExpression:
23171     allConstants = true;
23172     argsToWatch = [];
23173     forEach(ast.properties, function(property) {
23174       findConstantAndWatchExpressions(property.value, $filter);
23175       allConstants = allConstants && property.value.constant;
23176       if (!property.value.constant) {
23177         argsToWatch.push.apply(argsToWatch, property.value.toWatch);
23178       }
23179     });
23180     ast.constant = allConstants;
23181     ast.toWatch = argsToWatch;
23182     break;
23183   case AST.ThisExpression:
23184     ast.constant = false;
23185     ast.toWatch = [];
23186     break;
23187   case AST.LocalsExpression:
23188     ast.constant = false;
23189     ast.toWatch = [];
23190     break;
23191   }
23192 }
23193
23194 function getInputs(body) {
23195   if (body.length != 1) return;
23196   var lastExpression = body[0].expression;
23197   var candidate = lastExpression.toWatch;
23198   if (candidate.length !== 1) return candidate;
23199   return candidate[0] !== lastExpression ? candidate : undefined;
23200 }
23201
23202 function isAssignable(ast) {
23203   return ast.type === AST.Identifier || ast.type === AST.MemberExpression;
23204 }
23205
23206 function assignableAST(ast) {
23207   if (ast.body.length === 1 && isAssignable(ast.body[0].expression)) {
23208     return {type: AST.AssignmentExpression, left: ast.body[0].expression, right: {type: AST.NGValueParameter}, operator: '='};
23209   }
23210 }
23211
23212 function isLiteral(ast) {
23213   return ast.body.length === 0 ||
23214       ast.body.length === 1 && (
23215       ast.body[0].expression.type === AST.Literal ||
23216       ast.body[0].expression.type === AST.ArrayExpression ||
23217       ast.body[0].expression.type === AST.ObjectExpression);
23218 }
23219
23220 function isConstant(ast) {
23221   return ast.constant;
23222 }
23223
23224 function ASTCompiler(astBuilder, $filter) {
23225   this.astBuilder = astBuilder;
23226   this.$filter = $filter;
23227 }
23228
23229 ASTCompiler.prototype = {
23230   compile: function(expression, expensiveChecks) {
23231     var self = this;
23232     var ast = this.astBuilder.ast(expression);
23233     this.state = {
23234       nextId: 0,
23235       filters: {},
23236       expensiveChecks: expensiveChecks,
23237       fn: {vars: [], body: [], own: {}},
23238       assign: {vars: [], body: [], own: {}},
23239       inputs: []
23240     };
23241     findConstantAndWatchExpressions(ast, self.$filter);
23242     var extra = '';
23243     var assignable;
23244     this.stage = 'assign';
23245     if ((assignable = assignableAST(ast))) {
23246       this.state.computing = 'assign';
23247       var result = this.nextId();
23248       this.recurse(assignable, result);
23249       this.return_(result);
23250       extra = 'fn.assign=' + this.generateFunction('assign', 's,v,l');
23251     }
23252     var toWatch = getInputs(ast.body);
23253     self.stage = 'inputs';
23254     forEach(toWatch, function(watch, key) {
23255       var fnKey = 'fn' + key;
23256       self.state[fnKey] = {vars: [], body: [], own: {}};
23257       self.state.computing = fnKey;
23258       var intoId = self.nextId();
23259       self.recurse(watch, intoId);
23260       self.return_(intoId);
23261       self.state.inputs.push(fnKey);
23262       watch.watchId = key;
23263     });
23264     this.state.computing = 'fn';
23265     this.stage = 'main';
23266     this.recurse(ast);
23267     var fnString =
23268       // The build and minification steps remove the string "use strict" from the code, but this is done using a regex.
23269       // This is a workaround for this until we do a better job at only removing the prefix only when we should.
23270       '"' + this.USE + ' ' + this.STRICT + '";\n' +
23271       this.filterPrefix() +
23272       'var fn=' + this.generateFunction('fn', 's,l,a,i') +
23273       extra +
23274       this.watchFns() +
23275       'return fn;';
23276
23277     /* jshint -W054 */
23278     var fn = (new Function('$filter',
23279         'ensureSafeMemberName',
23280         'ensureSafeObject',
23281         'ensureSafeFunction',
23282         'getStringValue',
23283         'ensureSafeAssignContext',
23284         'ifDefined',
23285         'plus',
23286         'text',
23287         fnString))(
23288           this.$filter,
23289           ensureSafeMemberName,
23290           ensureSafeObject,
23291           ensureSafeFunction,
23292           getStringValue,
23293           ensureSafeAssignContext,
23294           ifDefined,
23295           plusFn,
23296           expression);
23297     /* jshint +W054 */
23298     this.state = this.stage = undefined;
23299     fn.literal = isLiteral(ast);
23300     fn.constant = isConstant(ast);
23301     return fn;
23302   },
23303
23304   USE: 'use',
23305
23306   STRICT: 'strict',
23307
23308   watchFns: function() {
23309     var result = [];
23310     var fns = this.state.inputs;
23311     var self = this;
23312     forEach(fns, function(name) {
23313       result.push('var ' + name + '=' + self.generateFunction(name, 's'));
23314     });
23315     if (fns.length) {
23316       result.push('fn.inputs=[' + fns.join(',') + '];');
23317     }
23318     return result.join('');
23319   },
23320
23321   generateFunction: function(name, params) {
23322     return 'function(' + params + '){' +
23323         this.varsPrefix(name) +
23324         this.body(name) +
23325         '};';
23326   },
23327
23328   filterPrefix: function() {
23329     var parts = [];
23330     var self = this;
23331     forEach(this.state.filters, function(id, filter) {
23332       parts.push(id + '=$filter(' + self.escape(filter) + ')');
23333     });
23334     if (parts.length) return 'var ' + parts.join(',') + ';';
23335     return '';
23336   },
23337
23338   varsPrefix: function(section) {
23339     return this.state[section].vars.length ? 'var ' + this.state[section].vars.join(',') + ';' : '';
23340   },
23341
23342   body: function(section) {
23343     return this.state[section].body.join('');
23344   },
23345
23346   recurse: function(ast, intoId, nameId, recursionFn, create, skipWatchIdCheck) {
23347     var left, right, self = this, args, expression;
23348     recursionFn = recursionFn || noop;
23349     if (!skipWatchIdCheck && isDefined(ast.watchId)) {
23350       intoId = intoId || this.nextId();
23351       this.if_('i',
23352         this.lazyAssign(intoId, this.computedMember('i', ast.watchId)),
23353         this.lazyRecurse(ast, intoId, nameId, recursionFn, create, true)
23354       );
23355       return;
23356     }
23357     switch (ast.type) {
23358     case AST.Program:
23359       forEach(ast.body, function(expression, pos) {
23360         self.recurse(expression.expression, undefined, undefined, function(expr) { right = expr; });
23361         if (pos !== ast.body.length - 1) {
23362           self.current().body.push(right, ';');
23363         } else {
23364           self.return_(right);
23365         }
23366       });
23367       break;
23368     case AST.Literal:
23369       expression = this.escape(ast.value);
23370       this.assign(intoId, expression);
23371       recursionFn(expression);
23372       break;
23373     case AST.UnaryExpression:
23374       this.recurse(ast.argument, undefined, undefined, function(expr) { right = expr; });
23375       expression = ast.operator + '(' + this.ifDefined(right, 0) + ')';
23376       this.assign(intoId, expression);
23377       recursionFn(expression);
23378       break;
23379     case AST.BinaryExpression:
23380       this.recurse(ast.left, undefined, undefined, function(expr) { left = expr; });
23381       this.recurse(ast.right, undefined, undefined, function(expr) { right = expr; });
23382       if (ast.operator === '+') {
23383         expression = this.plus(left, right);
23384       } else if (ast.operator === '-') {
23385         expression = this.ifDefined(left, 0) + ast.operator + this.ifDefined(right, 0);
23386       } else {
23387         expression = '(' + left + ')' + ast.operator + '(' + right + ')';
23388       }
23389       this.assign(intoId, expression);
23390       recursionFn(expression);
23391       break;
23392     case AST.LogicalExpression:
23393       intoId = intoId || this.nextId();
23394       self.recurse(ast.left, intoId);
23395       self.if_(ast.operator === '&&' ? intoId : self.not(intoId), self.lazyRecurse(ast.right, intoId));
23396       recursionFn(intoId);
23397       break;
23398     case AST.ConditionalExpression:
23399       intoId = intoId || this.nextId();
23400       self.recurse(ast.test, intoId);
23401       self.if_(intoId, self.lazyRecurse(ast.alternate, intoId), self.lazyRecurse(ast.consequent, intoId));
23402       recursionFn(intoId);
23403       break;
23404     case AST.Identifier:
23405       intoId = intoId || this.nextId();
23406       if (nameId) {
23407         nameId.context = self.stage === 'inputs' ? 's' : this.assign(this.nextId(), this.getHasOwnProperty('l', ast.name) + '?l:s');
23408         nameId.computed = false;
23409         nameId.name = ast.name;
23410       }
23411       ensureSafeMemberName(ast.name);
23412       self.if_(self.stage === 'inputs' || self.not(self.getHasOwnProperty('l', ast.name)),
23413         function() {
23414           self.if_(self.stage === 'inputs' || 's', function() {
23415             if (create && create !== 1) {
23416               self.if_(
23417                 self.not(self.nonComputedMember('s', ast.name)),
23418                 self.lazyAssign(self.nonComputedMember('s', ast.name), '{}'));
23419             }
23420             self.assign(intoId, self.nonComputedMember('s', ast.name));
23421           });
23422         }, intoId && self.lazyAssign(intoId, self.nonComputedMember('l', ast.name))
23423         );
23424       if (self.state.expensiveChecks || isPossiblyDangerousMemberName(ast.name)) {
23425         self.addEnsureSafeObject(intoId);
23426       }
23427       recursionFn(intoId);
23428       break;
23429     case AST.MemberExpression:
23430       left = nameId && (nameId.context = this.nextId()) || this.nextId();
23431       intoId = intoId || this.nextId();
23432       self.recurse(ast.object, left, undefined, function() {
23433         self.if_(self.notNull(left), function() {
23434           if (create && create !== 1) {
23435             self.addEnsureSafeAssignContext(left);
23436           }
23437           if (ast.computed) {
23438             right = self.nextId();
23439             self.recurse(ast.property, right);
23440             self.getStringValue(right);
23441             self.addEnsureSafeMemberName(right);
23442             if (create && create !== 1) {
23443               self.if_(self.not(self.computedMember(left, right)), self.lazyAssign(self.computedMember(left, right), '{}'));
23444             }
23445             expression = self.ensureSafeObject(self.computedMember(left, right));
23446             self.assign(intoId, expression);
23447             if (nameId) {
23448               nameId.computed = true;
23449               nameId.name = right;
23450             }
23451           } else {
23452             ensureSafeMemberName(ast.property.name);
23453             if (create && create !== 1) {
23454               self.if_(self.not(self.nonComputedMember(left, ast.property.name)), self.lazyAssign(self.nonComputedMember(left, ast.property.name), '{}'));
23455             }
23456             expression = self.nonComputedMember(left, ast.property.name);
23457             if (self.state.expensiveChecks || isPossiblyDangerousMemberName(ast.property.name)) {
23458               expression = self.ensureSafeObject(expression);
23459             }
23460             self.assign(intoId, expression);
23461             if (nameId) {
23462               nameId.computed = false;
23463               nameId.name = ast.property.name;
23464             }
23465           }
23466         }, function() {
23467           self.assign(intoId, 'undefined');
23468         });
23469         recursionFn(intoId);
23470       }, !!create);
23471       break;
23472     case AST.CallExpression:
23473       intoId = intoId || this.nextId();
23474       if (ast.filter) {
23475         right = self.filter(ast.callee.name);
23476         args = [];
23477         forEach(ast.arguments, function(expr) {
23478           var argument = self.nextId();
23479           self.recurse(expr, argument);
23480           args.push(argument);
23481         });
23482         expression = right + '(' + args.join(',') + ')';
23483         self.assign(intoId, expression);
23484         recursionFn(intoId);
23485       } else {
23486         right = self.nextId();
23487         left = {};
23488         args = [];
23489         self.recurse(ast.callee, right, left, function() {
23490           self.if_(self.notNull(right), function() {
23491             self.addEnsureSafeFunction(right);
23492             forEach(ast.arguments, function(expr) {
23493               self.recurse(expr, self.nextId(), undefined, function(argument) {
23494                 args.push(self.ensureSafeObject(argument));
23495               });
23496             });
23497             if (left.name) {
23498               if (!self.state.expensiveChecks) {
23499                 self.addEnsureSafeObject(left.context);
23500               }
23501               expression = self.member(left.context, left.name, left.computed) + '(' + args.join(',') + ')';
23502             } else {
23503               expression = right + '(' + args.join(',') + ')';
23504             }
23505             expression = self.ensureSafeObject(expression);
23506             self.assign(intoId, expression);
23507           }, function() {
23508             self.assign(intoId, 'undefined');
23509           });
23510           recursionFn(intoId);
23511         });
23512       }
23513       break;
23514     case AST.AssignmentExpression:
23515       right = this.nextId();
23516       left = {};
23517       if (!isAssignable(ast.left)) {
23518         throw $parseMinErr('lval', 'Trying to assign a value to a non l-value');
23519       }
23520       this.recurse(ast.left, undefined, left, function() {
23521         self.if_(self.notNull(left.context), function() {
23522           self.recurse(ast.right, right);
23523           self.addEnsureSafeObject(self.member(left.context, left.name, left.computed));
23524           self.addEnsureSafeAssignContext(left.context);
23525           expression = self.member(left.context, left.name, left.computed) + ast.operator + right;
23526           self.assign(intoId, expression);
23527           recursionFn(intoId || expression);
23528         });
23529       }, 1);
23530       break;
23531     case AST.ArrayExpression:
23532       args = [];
23533       forEach(ast.elements, function(expr) {
23534         self.recurse(expr, self.nextId(), undefined, function(argument) {
23535           args.push(argument);
23536         });
23537       });
23538       expression = '[' + args.join(',') + ']';
23539       this.assign(intoId, expression);
23540       recursionFn(expression);
23541       break;
23542     case AST.ObjectExpression:
23543       args = [];
23544       forEach(ast.properties, function(property) {
23545         self.recurse(property.value, self.nextId(), undefined, function(expr) {
23546           args.push(self.escape(
23547               property.key.type === AST.Identifier ? property.key.name :
23548                 ('' + property.key.value)) +
23549               ':' + expr);
23550         });
23551       });
23552       expression = '{' + args.join(',') + '}';
23553       this.assign(intoId, expression);
23554       recursionFn(expression);
23555       break;
23556     case AST.ThisExpression:
23557       this.assign(intoId, 's');
23558       recursionFn('s');
23559       break;
23560     case AST.LocalsExpression:
23561       this.assign(intoId, 'l');
23562       recursionFn('l');
23563       break;
23564     case AST.NGValueParameter:
23565       this.assign(intoId, 'v');
23566       recursionFn('v');
23567       break;
23568     }
23569   },
23570
23571   getHasOwnProperty: function(element, property) {
23572     var key = element + '.' + property;
23573     var own = this.current().own;
23574     if (!own.hasOwnProperty(key)) {
23575       own[key] = this.nextId(false, element + '&&(' + this.escape(property) + ' in ' + element + ')');
23576     }
23577     return own[key];
23578   },
23579
23580   assign: function(id, value) {
23581     if (!id) return;
23582     this.current().body.push(id, '=', value, ';');
23583     return id;
23584   },
23585
23586   filter: function(filterName) {
23587     if (!this.state.filters.hasOwnProperty(filterName)) {
23588       this.state.filters[filterName] = this.nextId(true);
23589     }
23590     return this.state.filters[filterName];
23591   },
23592
23593   ifDefined: function(id, defaultValue) {
23594     return 'ifDefined(' + id + ',' + this.escape(defaultValue) + ')';
23595   },
23596
23597   plus: function(left, right) {
23598     return 'plus(' + left + ',' + right + ')';
23599   },
23600
23601   return_: function(id) {
23602     this.current().body.push('return ', id, ';');
23603   },
23604
23605   if_: function(test, alternate, consequent) {
23606     if (test === true) {
23607       alternate();
23608     } else {
23609       var body = this.current().body;
23610       body.push('if(', test, '){');
23611       alternate();
23612       body.push('}');
23613       if (consequent) {
23614         body.push('else{');
23615         consequent();
23616         body.push('}');
23617       }
23618     }
23619   },
23620
23621   not: function(expression) {
23622     return '!(' + expression + ')';
23623   },
23624
23625   notNull: function(expression) {
23626     return expression + '!=null';
23627   },
23628
23629   nonComputedMember: function(left, right) {
23630     return left + '.' + right;
23631   },
23632
23633   computedMember: function(left, right) {
23634     return left + '[' + right + ']';
23635   },
23636
23637   member: function(left, right, computed) {
23638     if (computed) return this.computedMember(left, right);
23639     return this.nonComputedMember(left, right);
23640   },
23641
23642   addEnsureSafeObject: function(item) {
23643     this.current().body.push(this.ensureSafeObject(item), ';');
23644   },
23645
23646   addEnsureSafeMemberName: function(item) {
23647     this.current().body.push(this.ensureSafeMemberName(item), ';');
23648   },
23649
23650   addEnsureSafeFunction: function(item) {
23651     this.current().body.push(this.ensureSafeFunction(item), ';');
23652   },
23653
23654   addEnsureSafeAssignContext: function(item) {
23655     this.current().body.push(this.ensureSafeAssignContext(item), ';');
23656   },
23657
23658   ensureSafeObject: function(item) {
23659     return 'ensureSafeObject(' + item + ',text)';
23660   },
23661
23662   ensureSafeMemberName: function(item) {
23663     return 'ensureSafeMemberName(' + item + ',text)';
23664   },
23665
23666   ensureSafeFunction: function(item) {
23667     return 'ensureSafeFunction(' + item + ',text)';
23668   },
23669
23670   getStringValue: function(item) {
23671     this.assign(item, 'getStringValue(' + item + ')');
23672   },
23673
23674   ensureSafeAssignContext: function(item) {
23675     return 'ensureSafeAssignContext(' + item + ',text)';
23676   },
23677
23678   lazyRecurse: function(ast, intoId, nameId, recursionFn, create, skipWatchIdCheck) {
23679     var self = this;
23680     return function() {
23681       self.recurse(ast, intoId, nameId, recursionFn, create, skipWatchIdCheck);
23682     };
23683   },
23684
23685   lazyAssign: function(id, value) {
23686     var self = this;
23687     return function() {
23688       self.assign(id, value);
23689     };
23690   },
23691
23692   stringEscapeRegex: /[^ a-zA-Z0-9]/g,
23693
23694   stringEscapeFn: function(c) {
23695     return '\\u' + ('0000' + c.charCodeAt(0).toString(16)).slice(-4);
23696   },
23697
23698   escape: function(value) {
23699     if (isString(value)) return "'" + value.replace(this.stringEscapeRegex, this.stringEscapeFn) + "'";
23700     if (isNumber(value)) return value.toString();
23701     if (value === true) return 'true';
23702     if (value === false) return 'false';
23703     if (value === null) return 'null';
23704     if (typeof value === 'undefined') return 'undefined';
23705
23706     throw $parseMinErr('esc', 'IMPOSSIBLE');
23707   },
23708
23709   nextId: function(skip, init) {
23710     var id = 'v' + (this.state.nextId++);
23711     if (!skip) {
23712       this.current().vars.push(id + (init ? '=' + init : ''));
23713     }
23714     return id;
23715   },
23716
23717   current: function() {
23718     return this.state[this.state.computing];
23719   }
23720 };
23721
23722
23723 function ASTInterpreter(astBuilder, $filter) {
23724   this.astBuilder = astBuilder;
23725   this.$filter = $filter;
23726 }
23727
23728 ASTInterpreter.prototype = {
23729   compile: function(expression, expensiveChecks) {
23730     var self = this;
23731     var ast = this.astBuilder.ast(expression);
23732     this.expression = expression;
23733     this.expensiveChecks = expensiveChecks;
23734     findConstantAndWatchExpressions(ast, self.$filter);
23735     var assignable;
23736     var assign;
23737     if ((assignable = assignableAST(ast))) {
23738       assign = this.recurse(assignable);
23739     }
23740     var toWatch = getInputs(ast.body);
23741     var inputs;
23742     if (toWatch) {
23743       inputs = [];
23744       forEach(toWatch, function(watch, key) {
23745         var input = self.recurse(watch);
23746         watch.input = input;
23747         inputs.push(input);
23748         watch.watchId = key;
23749       });
23750     }
23751     var expressions = [];
23752     forEach(ast.body, function(expression) {
23753       expressions.push(self.recurse(expression.expression));
23754     });
23755     var fn = ast.body.length === 0 ? function() {} :
23756              ast.body.length === 1 ? expressions[0] :
23757              function(scope, locals) {
23758                var lastValue;
23759                forEach(expressions, function(exp) {
23760                  lastValue = exp(scope, locals);
23761                });
23762                return lastValue;
23763              };
23764     if (assign) {
23765       fn.assign = function(scope, value, locals) {
23766         return assign(scope, locals, value);
23767       };
23768     }
23769     if (inputs) {
23770       fn.inputs = inputs;
23771     }
23772     fn.literal = isLiteral(ast);
23773     fn.constant = isConstant(ast);
23774     return fn;
23775   },
23776
23777   recurse: function(ast, context, create) {
23778     var left, right, self = this, args, expression;
23779     if (ast.input) {
23780       return this.inputs(ast.input, ast.watchId);
23781     }
23782     switch (ast.type) {
23783     case AST.Literal:
23784       return this.value(ast.value, context);
23785     case AST.UnaryExpression:
23786       right = this.recurse(ast.argument);
23787       return this['unary' + ast.operator](right, context);
23788     case AST.BinaryExpression:
23789       left = this.recurse(ast.left);
23790       right = this.recurse(ast.right);
23791       return this['binary' + ast.operator](left, right, context);
23792     case AST.LogicalExpression:
23793       left = this.recurse(ast.left);
23794       right = this.recurse(ast.right);
23795       return this['binary' + ast.operator](left, right, context);
23796     case AST.ConditionalExpression:
23797       return this['ternary?:'](
23798         this.recurse(ast.test),
23799         this.recurse(ast.alternate),
23800         this.recurse(ast.consequent),
23801         context
23802       );
23803     case AST.Identifier:
23804       ensureSafeMemberName(ast.name, self.expression);
23805       return self.identifier(ast.name,
23806                              self.expensiveChecks || isPossiblyDangerousMemberName(ast.name),
23807                              context, create, self.expression);
23808     case AST.MemberExpression:
23809       left = this.recurse(ast.object, false, !!create);
23810       if (!ast.computed) {
23811         ensureSafeMemberName(ast.property.name, self.expression);
23812         right = ast.property.name;
23813       }
23814       if (ast.computed) right = this.recurse(ast.property);
23815       return ast.computed ?
23816         this.computedMember(left, right, context, create, self.expression) :
23817         this.nonComputedMember(left, right, self.expensiveChecks, context, create, self.expression);
23818     case AST.CallExpression:
23819       args = [];
23820       forEach(ast.arguments, function(expr) {
23821         args.push(self.recurse(expr));
23822       });
23823       if (ast.filter) right = this.$filter(ast.callee.name);
23824       if (!ast.filter) right = this.recurse(ast.callee, true);
23825       return ast.filter ?
23826         function(scope, locals, assign, inputs) {
23827           var values = [];
23828           for (var i = 0; i < args.length; ++i) {
23829             values.push(args[i](scope, locals, assign, inputs));
23830           }
23831           var value = right.apply(undefined, values, inputs);
23832           return context ? {context: undefined, name: undefined, value: value} : value;
23833         } :
23834         function(scope, locals, assign, inputs) {
23835           var rhs = right(scope, locals, assign, inputs);
23836           var value;
23837           if (rhs.value != null) {
23838             ensureSafeObject(rhs.context, self.expression);
23839             ensureSafeFunction(rhs.value, self.expression);
23840             var values = [];
23841             for (var i = 0; i < args.length; ++i) {
23842               values.push(ensureSafeObject(args[i](scope, locals, assign, inputs), self.expression));
23843             }
23844             value = ensureSafeObject(rhs.value.apply(rhs.context, values), self.expression);
23845           }
23846           return context ? {value: value} : value;
23847         };
23848     case AST.AssignmentExpression:
23849       left = this.recurse(ast.left, true, 1);
23850       right = this.recurse(ast.right);
23851       return function(scope, locals, assign, inputs) {
23852         var lhs = left(scope, locals, assign, inputs);
23853         var rhs = right(scope, locals, assign, inputs);
23854         ensureSafeObject(lhs.value, self.expression);
23855         ensureSafeAssignContext(lhs.context);
23856         lhs.context[lhs.name] = rhs;
23857         return context ? {value: rhs} : rhs;
23858       };
23859     case AST.ArrayExpression:
23860       args = [];
23861       forEach(ast.elements, function(expr) {
23862         args.push(self.recurse(expr));
23863       });
23864       return function(scope, locals, assign, inputs) {
23865         var value = [];
23866         for (var i = 0; i < args.length; ++i) {
23867           value.push(args[i](scope, locals, assign, inputs));
23868         }
23869         return context ? {value: value} : value;
23870       };
23871     case AST.ObjectExpression:
23872       args = [];
23873       forEach(ast.properties, function(property) {
23874         args.push({key: property.key.type === AST.Identifier ?
23875                         property.key.name :
23876                         ('' + property.key.value),
23877                    value: self.recurse(property.value)
23878         });
23879       });
23880       return function(scope, locals, assign, inputs) {
23881         var value = {};
23882         for (var i = 0; i < args.length; ++i) {
23883           value[args[i].key] = args[i].value(scope, locals, assign, inputs);
23884         }
23885         return context ? {value: value} : value;
23886       };
23887     case AST.ThisExpression:
23888       return function(scope) {
23889         return context ? {value: scope} : scope;
23890       };
23891     case AST.LocalsExpression:
23892       return function(scope, locals) {
23893         return context ? {value: locals} : locals;
23894       };
23895     case AST.NGValueParameter:
23896       return function(scope, locals, assign, inputs) {
23897         return context ? {value: assign} : assign;
23898       };
23899     }
23900   },
23901
23902   'unary+': function(argument, context) {
23903     return function(scope, locals, assign, inputs) {
23904       var arg = argument(scope, locals, assign, inputs);
23905       if (isDefined(arg)) {
23906         arg = +arg;
23907       } else {
23908         arg = 0;
23909       }
23910       return context ? {value: arg} : arg;
23911     };
23912   },
23913   'unary-': function(argument, context) {
23914     return function(scope, locals, assign, inputs) {
23915       var arg = argument(scope, locals, assign, inputs);
23916       if (isDefined(arg)) {
23917         arg = -arg;
23918       } else {
23919         arg = 0;
23920       }
23921       return context ? {value: arg} : arg;
23922     };
23923   },
23924   'unary!': function(argument, context) {
23925     return function(scope, locals, assign, inputs) {
23926       var arg = !argument(scope, locals, assign, inputs);
23927       return context ? {value: arg} : arg;
23928     };
23929   },
23930   'binary+': function(left, right, context) {
23931     return function(scope, locals, assign, inputs) {
23932       var lhs = left(scope, locals, assign, inputs);
23933       var rhs = right(scope, locals, assign, inputs);
23934       var arg = plusFn(lhs, rhs);
23935       return context ? {value: arg} : arg;
23936     };
23937   },
23938   'binary-': function(left, right, context) {
23939     return function(scope, locals, assign, inputs) {
23940       var lhs = left(scope, locals, assign, inputs);
23941       var rhs = right(scope, locals, assign, inputs);
23942       var arg = (isDefined(lhs) ? lhs : 0) - (isDefined(rhs) ? rhs : 0);
23943       return context ? {value: arg} : arg;
23944     };
23945   },
23946   'binary*': function(left, right, context) {
23947     return function(scope, locals, assign, inputs) {
23948       var arg = left(scope, locals, assign, inputs) * right(scope, locals, assign, inputs);
23949       return context ? {value: arg} : arg;
23950     };
23951   },
23952   'binary/': function(left, right, context) {
23953     return function(scope, locals, assign, inputs) {
23954       var arg = left(scope, locals, assign, inputs) / right(scope, locals, assign, inputs);
23955       return context ? {value: arg} : arg;
23956     };
23957   },
23958   'binary%': function(left, right, context) {
23959     return function(scope, locals, assign, inputs) {
23960       var arg = left(scope, locals, assign, inputs) % right(scope, locals, assign, inputs);
23961       return context ? {value: arg} : arg;
23962     };
23963   },
23964   'binary===': function(left, right, context) {
23965     return function(scope, locals, assign, inputs) {
23966       var arg = left(scope, locals, assign, inputs) === right(scope, locals, assign, inputs);
23967       return context ? {value: arg} : arg;
23968     };
23969   },
23970   'binary!==': function(left, right, context) {
23971     return function(scope, locals, assign, inputs) {
23972       var arg = left(scope, locals, assign, inputs) !== right(scope, locals, assign, inputs);
23973       return context ? {value: arg} : arg;
23974     };
23975   },
23976   'binary==': function(left, right, context) {
23977     return function(scope, locals, assign, inputs) {
23978       var arg = left(scope, locals, assign, inputs) == right(scope, locals, assign, inputs);
23979       return context ? {value: arg} : arg;
23980     };
23981   },
23982   'binary!=': function(left, right, context) {
23983     return function(scope, locals, assign, inputs) {
23984       var arg = left(scope, locals, assign, inputs) != right(scope, locals, assign, inputs);
23985       return context ? {value: arg} : arg;
23986     };
23987   },
23988   'binary<': function(left, right, context) {
23989     return function(scope, locals, assign, inputs) {
23990       var arg = left(scope, locals, assign, inputs) < right(scope, locals, assign, inputs);
23991       return context ? {value: arg} : arg;
23992     };
23993   },
23994   'binary>': function(left, right, context) {
23995     return function(scope, locals, assign, inputs) {
23996       var arg = left(scope, locals, assign, inputs) > right(scope, locals, assign, inputs);
23997       return context ? {value: arg} : arg;
23998     };
23999   },
24000   'binary<=': function(left, right, context) {
24001     return function(scope, locals, assign, inputs) {
24002       var arg = left(scope, locals, assign, inputs) <= right(scope, locals, assign, inputs);
24003       return context ? {value: arg} : arg;
24004     };
24005   },
24006   'binary>=': function(left, right, context) {
24007     return function(scope, locals, assign, inputs) {
24008       var arg = left(scope, locals, assign, inputs) >= right(scope, locals, assign, inputs);
24009       return context ? {value: arg} : arg;
24010     };
24011   },
24012   'binary&&': function(left, right, context) {
24013     return function(scope, locals, assign, inputs) {
24014       var arg = left(scope, locals, assign, inputs) && right(scope, locals, assign, inputs);
24015       return context ? {value: arg} : arg;
24016     };
24017   },
24018   'binary||': function(left, right, context) {
24019     return function(scope, locals, assign, inputs) {
24020       var arg = left(scope, locals, assign, inputs) || right(scope, locals, assign, inputs);
24021       return context ? {value: arg} : arg;
24022     };
24023   },
24024   'ternary?:': function(test, alternate, consequent, context) {
24025     return function(scope, locals, assign, inputs) {
24026       var arg = test(scope, locals, assign, inputs) ? alternate(scope, locals, assign, inputs) : consequent(scope, locals, assign, inputs);
24027       return context ? {value: arg} : arg;
24028     };
24029   },
24030   value: function(value, context) {
24031     return function() { return context ? {context: undefined, name: undefined, value: value} : value; };
24032   },
24033   identifier: function(name, expensiveChecks, context, create, expression) {
24034     return function(scope, locals, assign, inputs) {
24035       var base = locals && (name in locals) ? locals : scope;
24036       if (create && create !== 1 && base && !(base[name])) {
24037         base[name] = {};
24038       }
24039       var value = base ? base[name] : undefined;
24040       if (expensiveChecks) {
24041         ensureSafeObject(value, expression);
24042       }
24043       if (context) {
24044         return {context: base, name: name, value: value};
24045       } else {
24046         return value;
24047       }
24048     };
24049   },
24050   computedMember: function(left, right, context, create, expression) {
24051     return function(scope, locals, assign, inputs) {
24052       var lhs = left(scope, locals, assign, inputs);
24053       var rhs;
24054       var value;
24055       if (lhs != null) {
24056         rhs = right(scope, locals, assign, inputs);
24057         rhs = getStringValue(rhs);
24058         ensureSafeMemberName(rhs, expression);
24059         if (create && create !== 1) {
24060           ensureSafeAssignContext(lhs);
24061           if (lhs && !(lhs[rhs])) {
24062             lhs[rhs] = {};
24063           }
24064         }
24065         value = lhs[rhs];
24066         ensureSafeObject(value, expression);
24067       }
24068       if (context) {
24069         return {context: lhs, name: rhs, value: value};
24070       } else {
24071         return value;
24072       }
24073     };
24074   },
24075   nonComputedMember: function(left, right, expensiveChecks, context, create, expression) {
24076     return function(scope, locals, assign, inputs) {
24077       var lhs = left(scope, locals, assign, inputs);
24078       if (create && create !== 1) {
24079         ensureSafeAssignContext(lhs);
24080         if (lhs && !(lhs[right])) {
24081           lhs[right] = {};
24082         }
24083       }
24084       var value = lhs != null ? lhs[right] : undefined;
24085       if (expensiveChecks || isPossiblyDangerousMemberName(right)) {
24086         ensureSafeObject(value, expression);
24087       }
24088       if (context) {
24089         return {context: lhs, name: right, value: value};
24090       } else {
24091         return value;
24092       }
24093     };
24094   },
24095   inputs: function(input, watchId) {
24096     return function(scope, value, locals, inputs) {
24097       if (inputs) return inputs[watchId];
24098       return input(scope, value, locals);
24099     };
24100   }
24101 };
24102
24103 /**
24104  * @constructor
24105  */
24106 var Parser = function(lexer, $filter, options) {
24107   this.lexer = lexer;
24108   this.$filter = $filter;
24109   this.options = options;
24110   this.ast = new AST(this.lexer);
24111   this.astCompiler = options.csp ? new ASTInterpreter(this.ast, $filter) :
24112                                    new ASTCompiler(this.ast, $filter);
24113 };
24114
24115 Parser.prototype = {
24116   constructor: Parser,
24117
24118   parse: function(text) {
24119     return this.astCompiler.compile(text, this.options.expensiveChecks);
24120   }
24121 };
24122
24123 function isPossiblyDangerousMemberName(name) {
24124   return name == 'constructor';
24125 }
24126
24127 var objectValueOf = Object.prototype.valueOf;
24128
24129 function getValueOf(value) {
24130   return isFunction(value.valueOf) ? value.valueOf() : objectValueOf.call(value);
24131 }
24132
24133 ///////////////////////////////////
24134
24135 /**
24136  * @ngdoc service
24137  * @name $parse
24138  * @kind function
24139  *
24140  * @description
24141  *
24142  * Converts Angular {@link guide/expression expression} into a function.
24143  *
24144  * ```js
24145  *   var getter = $parse('user.name');
24146  *   var setter = getter.assign;
24147  *   var context = {user:{name:'angular'}};
24148  *   var locals = {user:{name:'local'}};
24149  *
24150  *   expect(getter(context)).toEqual('angular');
24151  *   setter(context, 'newValue');
24152  *   expect(context.user.name).toEqual('newValue');
24153  *   expect(getter(context, locals)).toEqual('local');
24154  * ```
24155  *
24156  *
24157  * @param {string} expression String expression to compile.
24158  * @returns {function(context, locals)} a function which represents the compiled expression:
24159  *
24160  *    * `context` – `{object}` – an object against which any expressions embedded in the strings
24161  *      are evaluated against (typically a scope object).
24162  *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
24163  *      `context`.
24164  *
24165  *    The returned function also has the following properties:
24166  *      * `literal` – `{boolean}` – whether the expression's top-level node is a JavaScript
24167  *        literal.
24168  *      * `constant` – `{boolean}` – whether the expression is made entirely of JavaScript
24169  *        constant literals.
24170  *      * `assign` – `{?function(context, value)}` – if the expression is assignable, this will be
24171  *        set to a function to change its value on the given context.
24172  *
24173  */
24174
24175
24176 /**
24177  * @ngdoc provider
24178  * @name $parseProvider
24179  *
24180  * @description
24181  * `$parseProvider` can be used for configuring the default behavior of the {@link ng.$parse $parse}
24182  *  service.
24183  */
24184 function $ParseProvider() {
24185   var cacheDefault = createMap();
24186   var cacheExpensive = createMap();
24187
24188   this.$get = ['$filter', function($filter) {
24189     var noUnsafeEval = csp().noUnsafeEval;
24190     var $parseOptions = {
24191           csp: noUnsafeEval,
24192           expensiveChecks: false
24193         },
24194         $parseOptionsExpensive = {
24195           csp: noUnsafeEval,
24196           expensiveChecks: true
24197         };
24198     var runningChecksEnabled = false;
24199
24200     $parse.$$runningExpensiveChecks = function() {
24201       return runningChecksEnabled;
24202     };
24203
24204     return $parse;
24205
24206     function $parse(exp, interceptorFn, expensiveChecks) {
24207       var parsedExpression, oneTime, cacheKey;
24208
24209       expensiveChecks = expensiveChecks || runningChecksEnabled;
24210
24211       switch (typeof exp) {
24212         case 'string':
24213           exp = exp.trim();
24214           cacheKey = exp;
24215
24216           var cache = (expensiveChecks ? cacheExpensive : cacheDefault);
24217           parsedExpression = cache[cacheKey];
24218
24219           if (!parsedExpression) {
24220             if (exp.charAt(0) === ':' && exp.charAt(1) === ':') {
24221               oneTime = true;
24222               exp = exp.substring(2);
24223             }
24224             var parseOptions = expensiveChecks ? $parseOptionsExpensive : $parseOptions;
24225             var lexer = new Lexer(parseOptions);
24226             var parser = new Parser(lexer, $filter, parseOptions);
24227             parsedExpression = parser.parse(exp);
24228             if (parsedExpression.constant) {
24229               parsedExpression.$$watchDelegate = constantWatchDelegate;
24230             } else if (oneTime) {
24231               parsedExpression.$$watchDelegate = parsedExpression.literal ?
24232                   oneTimeLiteralWatchDelegate : oneTimeWatchDelegate;
24233             } else if (parsedExpression.inputs) {
24234               parsedExpression.$$watchDelegate = inputsWatchDelegate;
24235             }
24236             if (expensiveChecks) {
24237               parsedExpression = expensiveChecksInterceptor(parsedExpression);
24238             }
24239             cache[cacheKey] = parsedExpression;
24240           }
24241           return addInterceptor(parsedExpression, interceptorFn);
24242
24243         case 'function':
24244           return addInterceptor(exp, interceptorFn);
24245
24246         default:
24247           return addInterceptor(noop, interceptorFn);
24248       }
24249     }
24250
24251     function expensiveChecksInterceptor(fn) {
24252       if (!fn) return fn;
24253       expensiveCheckFn.$$watchDelegate = fn.$$watchDelegate;
24254       expensiveCheckFn.assign = expensiveChecksInterceptor(fn.assign);
24255       expensiveCheckFn.constant = fn.constant;
24256       expensiveCheckFn.literal = fn.literal;
24257       for (var i = 0; fn.inputs && i < fn.inputs.length; ++i) {
24258         fn.inputs[i] = expensiveChecksInterceptor(fn.inputs[i]);
24259       }
24260       expensiveCheckFn.inputs = fn.inputs;
24261
24262       return expensiveCheckFn;
24263
24264       function expensiveCheckFn(scope, locals, assign, inputs) {
24265         var expensiveCheckOldValue = runningChecksEnabled;
24266         runningChecksEnabled = true;
24267         try {
24268           return fn(scope, locals, assign, inputs);
24269         } finally {
24270           runningChecksEnabled = expensiveCheckOldValue;
24271         }
24272       }
24273     }
24274
24275     function expressionInputDirtyCheck(newValue, oldValueOfValue) {
24276
24277       if (newValue == null || oldValueOfValue == null) { // null/undefined
24278         return newValue === oldValueOfValue;
24279       }
24280
24281       if (typeof newValue === 'object') {
24282
24283         // attempt to convert the value to a primitive type
24284         // TODO(docs): add a note to docs that by implementing valueOf even objects and arrays can
24285         //             be cheaply dirty-checked
24286         newValue = getValueOf(newValue);
24287
24288         if (typeof newValue === 'object') {
24289           // objects/arrays are not supported - deep-watching them would be too expensive
24290           return false;
24291         }
24292
24293         // fall-through to the primitive equality check
24294       }
24295
24296       //Primitive or NaN
24297       return newValue === oldValueOfValue || (newValue !== newValue && oldValueOfValue !== oldValueOfValue);
24298     }
24299
24300     function inputsWatchDelegate(scope, listener, objectEquality, parsedExpression, prettyPrintExpression) {
24301       var inputExpressions = parsedExpression.inputs;
24302       var lastResult;
24303
24304       if (inputExpressions.length === 1) {
24305         var oldInputValueOf = expressionInputDirtyCheck; // init to something unique so that equals check fails
24306         inputExpressions = inputExpressions[0];
24307         return scope.$watch(function expressionInputWatch(scope) {
24308           var newInputValue = inputExpressions(scope);
24309           if (!expressionInputDirtyCheck(newInputValue, oldInputValueOf)) {
24310             lastResult = parsedExpression(scope, undefined, undefined, [newInputValue]);
24311             oldInputValueOf = newInputValue && getValueOf(newInputValue);
24312           }
24313           return lastResult;
24314         }, listener, objectEquality, prettyPrintExpression);
24315       }
24316
24317       var oldInputValueOfValues = [];
24318       var oldInputValues = [];
24319       for (var i = 0, ii = inputExpressions.length; i < ii; i++) {
24320         oldInputValueOfValues[i] = expressionInputDirtyCheck; // init to something unique so that equals check fails
24321         oldInputValues[i] = null;
24322       }
24323
24324       return scope.$watch(function expressionInputsWatch(scope) {
24325         var changed = false;
24326
24327         for (var i = 0, ii = inputExpressions.length; i < ii; i++) {
24328           var newInputValue = inputExpressions[i](scope);
24329           if (changed || (changed = !expressionInputDirtyCheck(newInputValue, oldInputValueOfValues[i]))) {
24330             oldInputValues[i] = newInputValue;
24331             oldInputValueOfValues[i] = newInputValue && getValueOf(newInputValue);
24332           }
24333         }
24334
24335         if (changed) {
24336           lastResult = parsedExpression(scope, undefined, undefined, oldInputValues);
24337         }
24338
24339         return lastResult;
24340       }, listener, objectEquality, prettyPrintExpression);
24341     }
24342
24343     function oneTimeWatchDelegate(scope, listener, objectEquality, parsedExpression) {
24344       var unwatch, lastValue;
24345       return unwatch = scope.$watch(function oneTimeWatch(scope) {
24346         return parsedExpression(scope);
24347       }, function oneTimeListener(value, old, scope) {
24348         lastValue = value;
24349         if (isFunction(listener)) {
24350           listener.apply(this, arguments);
24351         }
24352         if (isDefined(value)) {
24353           scope.$$postDigest(function() {
24354             if (isDefined(lastValue)) {
24355               unwatch();
24356             }
24357           });
24358         }
24359       }, objectEquality);
24360     }
24361
24362     function oneTimeLiteralWatchDelegate(scope, listener, objectEquality, parsedExpression) {
24363       var unwatch, lastValue;
24364       return unwatch = scope.$watch(function oneTimeWatch(scope) {
24365         return parsedExpression(scope);
24366       }, function oneTimeListener(value, old, scope) {
24367         lastValue = value;
24368         if (isFunction(listener)) {
24369           listener.call(this, value, old, scope);
24370         }
24371         if (isAllDefined(value)) {
24372           scope.$$postDigest(function() {
24373             if (isAllDefined(lastValue)) unwatch();
24374           });
24375         }
24376       }, objectEquality);
24377
24378       function isAllDefined(value) {
24379         var allDefined = true;
24380         forEach(value, function(val) {
24381           if (!isDefined(val)) allDefined = false;
24382         });
24383         return allDefined;
24384       }
24385     }
24386
24387     function constantWatchDelegate(scope, listener, objectEquality, parsedExpression) {
24388       var unwatch;
24389       return unwatch = scope.$watch(function constantWatch(scope) {
24390         unwatch();
24391         return parsedExpression(scope);
24392       }, listener, objectEquality);
24393     }
24394
24395     function addInterceptor(parsedExpression, interceptorFn) {
24396       if (!interceptorFn) return parsedExpression;
24397       var watchDelegate = parsedExpression.$$watchDelegate;
24398       var useInputs = false;
24399
24400       var regularWatch =
24401           watchDelegate !== oneTimeLiteralWatchDelegate &&
24402           watchDelegate !== oneTimeWatchDelegate;
24403
24404       var fn = regularWatch ? function regularInterceptedExpression(scope, locals, assign, inputs) {
24405         var value = useInputs && inputs ? inputs[0] : parsedExpression(scope, locals, assign, inputs);
24406         return interceptorFn(value, scope, locals);
24407       } : function oneTimeInterceptedExpression(scope, locals, assign, inputs) {
24408         var value = parsedExpression(scope, locals, assign, inputs);
24409         var result = interceptorFn(value, scope, locals);
24410         // we only return the interceptor's result if the
24411         // initial value is defined (for bind-once)
24412         return isDefined(value) ? result : value;
24413       };
24414
24415       // Propagate $$watchDelegates other then inputsWatchDelegate
24416       if (parsedExpression.$$watchDelegate &&
24417           parsedExpression.$$watchDelegate !== inputsWatchDelegate) {
24418         fn.$$watchDelegate = parsedExpression.$$watchDelegate;
24419       } else if (!interceptorFn.$stateful) {
24420         // If there is an interceptor, but no watchDelegate then treat the interceptor like
24421         // we treat filters - it is assumed to be a pure function unless flagged with $stateful
24422         fn.$$watchDelegate = inputsWatchDelegate;
24423         useInputs = !parsedExpression.inputs;
24424         fn.inputs = parsedExpression.inputs ? parsedExpression.inputs : [parsedExpression];
24425       }
24426
24427       return fn;
24428     }
24429   }];
24430 }
24431
24432 /**
24433  * @ngdoc service
24434  * @name $q
24435  * @requires $rootScope
24436  *
24437  * @description
24438  * A service that helps you run functions asynchronously, and use their return values (or exceptions)
24439  * when they are done processing.
24440  *
24441  * This is an implementation of promises/deferred objects inspired by
24442  * [Kris Kowal's Q](https://github.com/kriskowal/q).
24443  *
24444  * $q can be used in two fashions --- one which is more similar to Kris Kowal's Q or jQuery's Deferred
24445  * implementations, and the other which resembles ES6 promises to some degree.
24446  *
24447  * # $q constructor
24448  *
24449  * The streamlined ES6 style promise is essentially just using $q as a constructor which takes a `resolver`
24450  * function as the first argument. This is similar to the native Promise implementation from ES6 Harmony,
24451  * see [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise).
24452  *
24453  * While the constructor-style use is supported, not all of the supporting methods from ES6 Harmony promises are
24454  * available yet.
24455  *
24456  * It can be used like so:
24457  *
24458  * ```js
24459  *   // for the purpose of this example let's assume that variables `$q` and `okToGreet`
24460  *   // are available in the current lexical scope (they could have been injected or passed in).
24461  *
24462  *   function asyncGreet(name) {
24463  *     // perform some asynchronous operation, resolve or reject the promise when appropriate.
24464  *     return $q(function(resolve, reject) {
24465  *       setTimeout(function() {
24466  *         if (okToGreet(name)) {
24467  *           resolve('Hello, ' + name + '!');
24468  *         } else {
24469  *           reject('Greeting ' + name + ' is not allowed.');
24470  *         }
24471  *       }, 1000);
24472  *     });
24473  *   }
24474  *
24475  *   var promise = asyncGreet('Robin Hood');
24476  *   promise.then(function(greeting) {
24477  *     alert('Success: ' + greeting);
24478  *   }, function(reason) {
24479  *     alert('Failed: ' + reason);
24480  *   });
24481  * ```
24482  *
24483  * Note: progress/notify callbacks are not currently supported via the ES6-style interface.
24484  *
24485  * Note: unlike ES6 behavior, an exception thrown in the constructor function will NOT implicitly reject the promise.
24486  *
24487  * However, the more traditional CommonJS-style usage is still available, and documented below.
24488  *
24489  * [The CommonJS Promise proposal](http://wiki.commonjs.org/wiki/Promises) describes a promise as an
24490  * interface for interacting with an object that represents the result of an action that is
24491  * performed asynchronously, and may or may not be finished at any given point in time.
24492  *
24493  * From the perspective of dealing with error handling, deferred and promise APIs are to
24494  * asynchronous programming what `try`, `catch` and `throw` keywords are to synchronous programming.
24495  *
24496  * ```js
24497  *   // for the purpose of this example let's assume that variables `$q` and `okToGreet`
24498  *   // are available in the current lexical scope (they could have been injected or passed in).
24499  *
24500  *   function asyncGreet(name) {
24501  *     var deferred = $q.defer();
24502  *
24503  *     setTimeout(function() {
24504  *       deferred.notify('About to greet ' + name + '.');
24505  *
24506  *       if (okToGreet(name)) {
24507  *         deferred.resolve('Hello, ' + name + '!');
24508  *       } else {
24509  *         deferred.reject('Greeting ' + name + ' is not allowed.');
24510  *       }
24511  *     }, 1000);
24512  *
24513  *     return deferred.promise;
24514  *   }
24515  *
24516  *   var promise = asyncGreet('Robin Hood');
24517  *   promise.then(function(greeting) {
24518  *     alert('Success: ' + greeting);
24519  *   }, function(reason) {
24520  *     alert('Failed: ' + reason);
24521  *   }, function(update) {
24522  *     alert('Got notification: ' + update);
24523  *   });
24524  * ```
24525  *
24526  * At first it might not be obvious why this extra complexity is worth the trouble. The payoff
24527  * comes in the way of guarantees that promise and deferred APIs make, see
24528  * https://github.com/kriskowal/uncommonjs/blob/master/promises/specification.md.
24529  *
24530  * Additionally the promise api allows for composition that is very hard to do with the
24531  * traditional callback ([CPS](http://en.wikipedia.org/wiki/Continuation-passing_style)) approach.
24532  * For more on this please see the [Q documentation](https://github.com/kriskowal/q) especially the
24533  * section on serial or parallel joining of promises.
24534  *
24535  * # The Deferred API
24536  *
24537  * A new instance of deferred is constructed by calling `$q.defer()`.
24538  *
24539  * The purpose of the deferred object is to expose the associated Promise instance as well as APIs
24540  * that can be used for signaling the successful or unsuccessful completion, as well as the status
24541  * of the task.
24542  *
24543  * **Methods**
24544  *
24545  * - `resolve(value)` – resolves the derived promise with the `value`. If the value is a rejection
24546  *   constructed via `$q.reject`, the promise will be rejected instead.
24547  * - `reject(reason)` – rejects the derived promise with the `reason`. This is equivalent to
24548  *   resolving it with a rejection constructed via `$q.reject`.
24549  * - `notify(value)` - provides updates on the status of the promise's execution. This may be called
24550  *   multiple times before the promise is either resolved or rejected.
24551  *
24552  * **Properties**
24553  *
24554  * - promise – `{Promise}` – promise object associated with this deferred.
24555  *
24556  *
24557  * # The Promise API
24558  *
24559  * A new promise instance is created when a deferred instance is created and can be retrieved by
24560  * calling `deferred.promise`.
24561  *
24562  * The purpose of the promise object is to allow for interested parties to get access to the result
24563  * of the deferred task when it completes.
24564  *
24565  * **Methods**
24566  *
24567  * - `then(successCallback, errorCallback, notifyCallback)` – regardless of when the promise was or
24568  *   will be resolved or rejected, `then` calls one of the success or error callbacks asynchronously
24569  *   as soon as the result is available. The callbacks are called with a single argument: the result
24570  *   or rejection reason. Additionally, the notify callback may be called zero or more times to
24571  *   provide a progress indication, before the promise is resolved or rejected.
24572  *
24573  *   This method *returns a new promise* which is resolved or rejected via the return value of the
24574  *   `successCallback`, `errorCallback` (unless that value is a promise, in which case it is resolved
24575  *   with the value which is resolved in that promise using
24576  *   [promise chaining](http://www.html5rocks.com/en/tutorials/es6/promises/#toc-promises-queues)).
24577  *   It also notifies via the return value of the `notifyCallback` method. The promise cannot be
24578  *   resolved or rejected from the notifyCallback method.
24579  *
24580  * - `catch(errorCallback)` – shorthand for `promise.then(null, errorCallback)`
24581  *
24582  * - `finally(callback, notifyCallback)` – allows you to observe either the fulfillment or rejection of a promise,
24583  *   but to do so without modifying the final value. This is useful to release resources or do some
24584  *   clean-up that needs to be done whether the promise was rejected or resolved. See the [full
24585  *   specification](https://github.com/kriskowal/q/wiki/API-Reference#promisefinallycallback) for
24586  *   more information.
24587  *
24588  * # Chaining promises
24589  *
24590  * Because calling the `then` method of a promise returns a new derived promise, it is easily
24591  * possible to create a chain of promises:
24592  *
24593  * ```js
24594  *   promiseB = promiseA.then(function(result) {
24595  *     return result + 1;
24596  *   });
24597  *
24598  *   // promiseB will be resolved immediately after promiseA is resolved and its value
24599  *   // will be the result of promiseA incremented by 1
24600  * ```
24601  *
24602  * It is possible to create chains of any length and since a promise can be resolved with another
24603  * promise (which will defer its resolution further), it is possible to pause/defer resolution of
24604  * the promises at any point in the chain. This makes it possible to implement powerful APIs like
24605  * $http's response interceptors.
24606  *
24607  *
24608  * # Differences between Kris Kowal's Q and $q
24609  *
24610  *  There are two main differences:
24611  *
24612  * - $q is integrated with the {@link ng.$rootScope.Scope} Scope model observation
24613  *   mechanism in angular, which means faster propagation of resolution or rejection into your
24614  *   models and avoiding unnecessary browser repaints, which would result in flickering UI.
24615  * - Q has many more features than $q, but that comes at a cost of bytes. $q is tiny, but contains
24616  *   all the important functionality needed for common async tasks.
24617  *
24618  *  # Testing
24619  *
24620  *  ```js
24621  *    it('should simulate promise', inject(function($q, $rootScope) {
24622  *      var deferred = $q.defer();
24623  *      var promise = deferred.promise;
24624  *      var resolvedValue;
24625  *
24626  *      promise.then(function(value) { resolvedValue = value; });
24627  *      expect(resolvedValue).toBeUndefined();
24628  *
24629  *      // Simulate resolving of promise
24630  *      deferred.resolve(123);
24631  *      // Note that the 'then' function does not get called synchronously.
24632  *      // This is because we want the promise API to always be async, whether or not
24633  *      // it got called synchronously or asynchronously.
24634  *      expect(resolvedValue).toBeUndefined();
24635  *
24636  *      // Propagate promise resolution to 'then' functions using $apply().
24637  *      $rootScope.$apply();
24638  *      expect(resolvedValue).toEqual(123);
24639  *    }));
24640  *  ```
24641  *
24642  * @param {function(function, function)} resolver Function which is responsible for resolving or
24643  *   rejecting the newly created promise. The first parameter is a function which resolves the
24644  *   promise, the second parameter is a function which rejects the promise.
24645  *
24646  * @returns {Promise} The newly created promise.
24647  */
24648 function $QProvider() {
24649
24650   this.$get = ['$rootScope', '$exceptionHandler', function($rootScope, $exceptionHandler) {
24651     return qFactory(function(callback) {
24652       $rootScope.$evalAsync(callback);
24653     }, $exceptionHandler);
24654   }];
24655 }
24656
24657 function $$QProvider() {
24658   this.$get = ['$browser', '$exceptionHandler', function($browser, $exceptionHandler) {
24659     return qFactory(function(callback) {
24660       $browser.defer(callback);
24661     }, $exceptionHandler);
24662   }];
24663 }
24664
24665 /**
24666  * Constructs a promise manager.
24667  *
24668  * @param {function(function)} nextTick Function for executing functions in the next turn.
24669  * @param {function(...*)} exceptionHandler Function into which unexpected exceptions are passed for
24670  *     debugging purposes.
24671  * @returns {object} Promise manager.
24672  */
24673 function qFactory(nextTick, exceptionHandler) {
24674   var $qMinErr = minErr('$q', TypeError);
24675
24676   /**
24677    * @ngdoc method
24678    * @name ng.$q#defer
24679    * @kind function
24680    *
24681    * @description
24682    * Creates a `Deferred` object which represents a task which will finish in the future.
24683    *
24684    * @returns {Deferred} Returns a new instance of deferred.
24685    */
24686   var defer = function() {
24687     var d = new Deferred();
24688     //Necessary to support unbound execution :/
24689     d.resolve = simpleBind(d, d.resolve);
24690     d.reject = simpleBind(d, d.reject);
24691     d.notify = simpleBind(d, d.notify);
24692     return d;
24693   };
24694
24695   function Promise() {
24696     this.$$state = { status: 0 };
24697   }
24698
24699   extend(Promise.prototype, {
24700     then: function(onFulfilled, onRejected, progressBack) {
24701       if (isUndefined(onFulfilled) && isUndefined(onRejected) && isUndefined(progressBack)) {
24702         return this;
24703       }
24704       var result = new Deferred();
24705
24706       this.$$state.pending = this.$$state.pending || [];
24707       this.$$state.pending.push([result, onFulfilled, onRejected, progressBack]);
24708       if (this.$$state.status > 0) scheduleProcessQueue(this.$$state);
24709
24710       return result.promise;
24711     },
24712
24713     "catch": function(callback) {
24714       return this.then(null, callback);
24715     },
24716
24717     "finally": function(callback, progressBack) {
24718       return this.then(function(value) {
24719         return handleCallback(value, true, callback);
24720       }, function(error) {
24721         return handleCallback(error, false, callback);
24722       }, progressBack);
24723     }
24724   });
24725
24726   //Faster, more basic than angular.bind http://jsperf.com/angular-bind-vs-custom-vs-native
24727   function simpleBind(context, fn) {
24728     return function(value) {
24729       fn.call(context, value);
24730     };
24731   }
24732
24733   function processQueue(state) {
24734     var fn, deferred, pending;
24735
24736     pending = state.pending;
24737     state.processScheduled = false;
24738     state.pending = undefined;
24739     for (var i = 0, ii = pending.length; i < ii; ++i) {
24740       deferred = pending[i][0];
24741       fn = pending[i][state.status];
24742       try {
24743         if (isFunction(fn)) {
24744           deferred.resolve(fn(state.value));
24745         } else if (state.status === 1) {
24746           deferred.resolve(state.value);
24747         } else {
24748           deferred.reject(state.value);
24749         }
24750       } catch (e) {
24751         deferred.reject(e);
24752         exceptionHandler(e);
24753       }
24754     }
24755   }
24756
24757   function scheduleProcessQueue(state) {
24758     if (state.processScheduled || !state.pending) return;
24759     state.processScheduled = true;
24760     nextTick(function() { processQueue(state); });
24761   }
24762
24763   function Deferred() {
24764     this.promise = new Promise();
24765   }
24766
24767   extend(Deferred.prototype, {
24768     resolve: function(val) {
24769       if (this.promise.$$state.status) return;
24770       if (val === this.promise) {
24771         this.$$reject($qMinErr(
24772           'qcycle',
24773           "Expected promise to be resolved with value other than itself '{0}'",
24774           val));
24775       } else {
24776         this.$$resolve(val);
24777       }
24778
24779     },
24780
24781     $$resolve: function(val) {
24782       var then;
24783       var that = this;
24784       var done = false;
24785       try {
24786         if ((isObject(val) || isFunction(val))) then = val && val.then;
24787         if (isFunction(then)) {
24788           this.promise.$$state.status = -1;
24789           then.call(val, resolvePromise, rejectPromise, simpleBind(this, this.notify));
24790         } else {
24791           this.promise.$$state.value = val;
24792           this.promise.$$state.status = 1;
24793           scheduleProcessQueue(this.promise.$$state);
24794         }
24795       } catch (e) {
24796         rejectPromise(e);
24797         exceptionHandler(e);
24798       }
24799
24800       function resolvePromise(val) {
24801         if (done) return;
24802         done = true;
24803         that.$$resolve(val);
24804       }
24805       function rejectPromise(val) {
24806         if (done) return;
24807         done = true;
24808         that.$$reject(val);
24809       }
24810     },
24811
24812     reject: function(reason) {
24813       if (this.promise.$$state.status) return;
24814       this.$$reject(reason);
24815     },
24816
24817     $$reject: function(reason) {
24818       this.promise.$$state.value = reason;
24819       this.promise.$$state.status = 2;
24820       scheduleProcessQueue(this.promise.$$state);
24821     },
24822
24823     notify: function(progress) {
24824       var callbacks = this.promise.$$state.pending;
24825
24826       if ((this.promise.$$state.status <= 0) && callbacks && callbacks.length) {
24827         nextTick(function() {
24828           var callback, result;
24829           for (var i = 0, ii = callbacks.length; i < ii; i++) {
24830             result = callbacks[i][0];
24831             callback = callbacks[i][3];
24832             try {
24833               result.notify(isFunction(callback) ? callback(progress) : progress);
24834             } catch (e) {
24835               exceptionHandler(e);
24836             }
24837           }
24838         });
24839       }
24840     }
24841   });
24842
24843   /**
24844    * @ngdoc method
24845    * @name $q#reject
24846    * @kind function
24847    *
24848    * @description
24849    * Creates a promise that is resolved as rejected with the specified `reason`. This api should be
24850    * used to forward rejection in a chain of promises. If you are dealing with the last promise in
24851    * a promise chain, you don't need to worry about it.
24852    *
24853    * When comparing deferreds/promises to the familiar behavior of try/catch/throw, think of
24854    * `reject` as the `throw` keyword in JavaScript. This also means that if you "catch" an error via
24855    * a promise error callback and you want to forward the error to the promise derived from the
24856    * current promise, you have to "rethrow" the error by returning a rejection constructed via
24857    * `reject`.
24858    *
24859    * ```js
24860    *   promiseB = promiseA.then(function(result) {
24861    *     // success: do something and resolve promiseB
24862    *     //          with the old or a new result
24863    *     return result;
24864    *   }, function(reason) {
24865    *     // error: handle the error if possible and
24866    *     //        resolve promiseB with newPromiseOrValue,
24867    *     //        otherwise forward the rejection to promiseB
24868    *     if (canHandle(reason)) {
24869    *      // handle the error and recover
24870    *      return newPromiseOrValue;
24871    *     }
24872    *     return $q.reject(reason);
24873    *   });
24874    * ```
24875    *
24876    * @param {*} reason Constant, message, exception or an object representing the rejection reason.
24877    * @returns {Promise} Returns a promise that was already resolved as rejected with the `reason`.
24878    */
24879   var reject = function(reason) {
24880     var result = new Deferred();
24881     result.reject(reason);
24882     return result.promise;
24883   };
24884
24885   var makePromise = function makePromise(value, resolved) {
24886     var result = new Deferred();
24887     if (resolved) {
24888       result.resolve(value);
24889     } else {
24890       result.reject(value);
24891     }
24892     return result.promise;
24893   };
24894
24895   var handleCallback = function handleCallback(value, isResolved, callback) {
24896     var callbackOutput = null;
24897     try {
24898       if (isFunction(callback)) callbackOutput = callback();
24899     } catch (e) {
24900       return makePromise(e, false);
24901     }
24902     if (isPromiseLike(callbackOutput)) {
24903       return callbackOutput.then(function() {
24904         return makePromise(value, isResolved);
24905       }, function(error) {
24906         return makePromise(error, false);
24907       });
24908     } else {
24909       return makePromise(value, isResolved);
24910     }
24911   };
24912
24913   /**
24914    * @ngdoc method
24915    * @name $q#when
24916    * @kind function
24917    *
24918    * @description
24919    * Wraps an object that might be a value or a (3rd party) then-able promise into a $q promise.
24920    * This is useful when you are dealing with an object that might or might not be a promise, or if
24921    * the promise comes from a source that can't be trusted.
24922    *
24923    * @param {*} value Value or a promise
24924    * @param {Function=} successCallback
24925    * @param {Function=} errorCallback
24926    * @param {Function=} progressCallback
24927    * @returns {Promise} Returns a promise of the passed value or promise
24928    */
24929
24930
24931   var when = function(value, callback, errback, progressBack) {
24932     var result = new Deferred();
24933     result.resolve(value);
24934     return result.promise.then(callback, errback, progressBack);
24935   };
24936
24937   /**
24938    * @ngdoc method
24939    * @name $q#resolve
24940    * @kind function
24941    *
24942    * @description
24943    * Alias of {@link ng.$q#when when} to maintain naming consistency with ES6.
24944    *
24945    * @param {*} value Value or a promise
24946    * @param {Function=} successCallback
24947    * @param {Function=} errorCallback
24948    * @param {Function=} progressCallback
24949    * @returns {Promise} Returns a promise of the passed value or promise
24950    */
24951   var resolve = when;
24952
24953   /**
24954    * @ngdoc method
24955    * @name $q#all
24956    * @kind function
24957    *
24958    * @description
24959    * Combines multiple promises into a single promise that is resolved when all of the input
24960    * promises are resolved.
24961    *
24962    * @param {Array.<Promise>|Object.<Promise>} promises An array or hash of promises.
24963    * @returns {Promise} Returns a single promise that will be resolved with an array/hash of values,
24964    *   each value corresponding to the promise at the same index/key in the `promises` array/hash.
24965    *   If any of the promises is resolved with a rejection, this resulting promise will be rejected
24966    *   with the same rejection value.
24967    */
24968
24969   function all(promises) {
24970     var deferred = new Deferred(),
24971         counter = 0,
24972         results = isArray(promises) ? [] : {};
24973
24974     forEach(promises, function(promise, key) {
24975       counter++;
24976       when(promise).then(function(value) {
24977         if (results.hasOwnProperty(key)) return;
24978         results[key] = value;
24979         if (!(--counter)) deferred.resolve(results);
24980       }, function(reason) {
24981         if (results.hasOwnProperty(key)) return;
24982         deferred.reject(reason);
24983       });
24984     });
24985
24986     if (counter === 0) {
24987       deferred.resolve(results);
24988     }
24989
24990     return deferred.promise;
24991   }
24992
24993   var $Q = function Q(resolver) {
24994     if (!isFunction(resolver)) {
24995       throw $qMinErr('norslvr', "Expected resolverFn, got '{0}'", resolver);
24996     }
24997
24998     var deferred = new Deferred();
24999
25000     function resolveFn(value) {
25001       deferred.resolve(value);
25002     }
25003
25004     function rejectFn(reason) {
25005       deferred.reject(reason);
25006     }
25007
25008     resolver(resolveFn, rejectFn);
25009
25010     return deferred.promise;
25011   };
25012
25013   // Let's make the instanceof operator work for promises, so that
25014   // `new $q(fn) instanceof $q` would evaluate to true.
25015   $Q.prototype = Promise.prototype;
25016
25017   $Q.defer = defer;
25018   $Q.reject = reject;
25019   $Q.when = when;
25020   $Q.resolve = resolve;
25021   $Q.all = all;
25022
25023   return $Q;
25024 }
25025
25026 function $$RAFProvider() { //rAF
25027   this.$get = ['$window', '$timeout', function($window, $timeout) {
25028     var requestAnimationFrame = $window.requestAnimationFrame ||
25029                                 $window.webkitRequestAnimationFrame;
25030
25031     var cancelAnimationFrame = $window.cancelAnimationFrame ||
25032                                $window.webkitCancelAnimationFrame ||
25033                                $window.webkitCancelRequestAnimationFrame;
25034
25035     var rafSupported = !!requestAnimationFrame;
25036     var raf = rafSupported
25037       ? function(fn) {
25038           var id = requestAnimationFrame(fn);
25039           return function() {
25040             cancelAnimationFrame(id);
25041           };
25042         }
25043       : function(fn) {
25044           var timer = $timeout(fn, 16.66, false); // 1000 / 60 = 16.666
25045           return function() {
25046             $timeout.cancel(timer);
25047           };
25048         };
25049
25050     raf.supported = rafSupported;
25051
25052     return raf;
25053   }];
25054 }
25055
25056 /**
25057  * DESIGN NOTES
25058  *
25059  * The design decisions behind the scope are heavily favored for speed and memory consumption.
25060  *
25061  * The typical use of scope is to watch the expressions, which most of the time return the same
25062  * value as last time so we optimize the operation.
25063  *
25064  * Closures construction is expensive in terms of speed as well as memory:
25065  *   - No closures, instead use prototypical inheritance for API
25066  *   - Internal state needs to be stored on scope directly, which means that private state is
25067  *     exposed as $$____ properties
25068  *
25069  * Loop operations are optimized by using while(count--) { ... }
25070  *   - This means that in order to keep the same order of execution as addition we have to add
25071  *     items to the array at the beginning (unshift) instead of at the end (push)
25072  *
25073  * Child scopes are created and removed often
25074  *   - Using an array would be slow since inserts in the middle are expensive; so we use linked lists
25075  *
25076  * There are fewer watches than observers. This is why you don't want the observer to be implemented
25077  * in the same way as watch. Watch requires return of the initialization function which is expensive
25078  * to construct.
25079  */
25080
25081
25082 /**
25083  * @ngdoc provider
25084  * @name $rootScopeProvider
25085  * @description
25086  *
25087  * Provider for the $rootScope service.
25088  */
25089
25090 /**
25091  * @ngdoc method
25092  * @name $rootScopeProvider#digestTtl
25093  * @description
25094  *
25095  * Sets the number of `$digest` iterations the scope should attempt to execute before giving up and
25096  * assuming that the model is unstable.
25097  *
25098  * The current default is 10 iterations.
25099  *
25100  * In complex applications it's possible that the dependencies between `$watch`s will result in
25101  * several digest iterations. However if an application needs more than the default 10 digest
25102  * iterations for its model to stabilize then you should investigate what is causing the model to
25103  * continuously change during the digest.
25104  *
25105  * Increasing the TTL could have performance implications, so you should not change it without
25106  * proper justification.
25107  *
25108  * @param {number} limit The number of digest iterations.
25109  */
25110
25111
25112 /**
25113  * @ngdoc service
25114  * @name $rootScope
25115  * @description
25116  *
25117  * Every application has a single root {@link ng.$rootScope.Scope scope}.
25118  * All other scopes are descendant scopes of the root scope. Scopes provide separation
25119  * between the model and the view, via a mechanism for watching the model for changes.
25120  * They also provide event emission/broadcast and subscription facility. See the
25121  * {@link guide/scope developer guide on scopes}.
25122  */
25123 function $RootScopeProvider() {
25124   var TTL = 10;
25125   var $rootScopeMinErr = minErr('$rootScope');
25126   var lastDirtyWatch = null;
25127   var applyAsyncId = null;
25128
25129   this.digestTtl = function(value) {
25130     if (arguments.length) {
25131       TTL = value;
25132     }
25133     return TTL;
25134   };
25135
25136   function createChildScopeClass(parent) {
25137     function ChildScope() {
25138       this.$$watchers = this.$$nextSibling =
25139           this.$$childHead = this.$$childTail = null;
25140       this.$$listeners = {};
25141       this.$$listenerCount = {};
25142       this.$$watchersCount = 0;
25143       this.$id = nextUid();
25144       this.$$ChildScope = null;
25145     }
25146     ChildScope.prototype = parent;
25147     return ChildScope;
25148   }
25149
25150   this.$get = ['$exceptionHandler', '$parse', '$browser',
25151       function($exceptionHandler, $parse, $browser) {
25152
25153     function destroyChildScope($event) {
25154         $event.currentScope.$$destroyed = true;
25155     }
25156
25157     function cleanUpScope($scope) {
25158
25159       if (msie === 9) {
25160         // There is a memory leak in IE9 if all child scopes are not disconnected
25161         // completely when a scope is destroyed. So this code will recurse up through
25162         // all this scopes children
25163         //
25164         // See issue https://github.com/angular/angular.js/issues/10706
25165         $scope.$$childHead && cleanUpScope($scope.$$childHead);
25166         $scope.$$nextSibling && cleanUpScope($scope.$$nextSibling);
25167       }
25168
25169       // The code below works around IE9 and V8's memory leaks
25170       //
25171       // See:
25172       // - https://code.google.com/p/v8/issues/detail?id=2073#c26
25173       // - https://github.com/angular/angular.js/issues/6794#issuecomment-38648909
25174       // - https://github.com/angular/angular.js/issues/1313#issuecomment-10378451
25175
25176       $scope.$parent = $scope.$$nextSibling = $scope.$$prevSibling = $scope.$$childHead =
25177           $scope.$$childTail = $scope.$root = $scope.$$watchers = null;
25178     }
25179
25180     /**
25181      * @ngdoc type
25182      * @name $rootScope.Scope
25183      *
25184      * @description
25185      * A root scope can be retrieved using the {@link ng.$rootScope $rootScope} key from the
25186      * {@link auto.$injector $injector}. Child scopes are created using the
25187      * {@link ng.$rootScope.Scope#$new $new()} method. (Most scopes are created automatically when
25188      * compiled HTML template is executed.) See also the {@link guide/scope Scopes guide} for
25189      * an in-depth introduction and usage examples.
25190      *
25191      *
25192      * # Inheritance
25193      * A scope can inherit from a parent scope, as in this example:
25194      * ```js
25195          var parent = $rootScope;
25196          var child = parent.$new();
25197
25198          parent.salutation = "Hello";
25199          expect(child.salutation).toEqual('Hello');
25200
25201          child.salutation = "Welcome";
25202          expect(child.salutation).toEqual('Welcome');
25203          expect(parent.salutation).toEqual('Hello');
25204      * ```
25205      *
25206      * When interacting with `Scope` in tests, additional helper methods are available on the
25207      * instances of `Scope` type. See {@link ngMock.$rootScope.Scope ngMock Scope} for additional
25208      * details.
25209      *
25210      *
25211      * @param {Object.<string, function()>=} providers Map of service factory which need to be
25212      *                                       provided for the current scope. Defaults to {@link ng}.
25213      * @param {Object.<string, *>=} instanceCache Provides pre-instantiated services which should
25214      *                              append/override services provided by `providers`. This is handy
25215      *                              when unit-testing and having the need to override a default
25216      *                              service.
25217      * @returns {Object} Newly created scope.
25218      *
25219      */
25220     function Scope() {
25221       this.$id = nextUid();
25222       this.$$phase = this.$parent = this.$$watchers =
25223                      this.$$nextSibling = this.$$prevSibling =
25224                      this.$$childHead = this.$$childTail = null;
25225       this.$root = this;
25226       this.$$destroyed = false;
25227       this.$$listeners = {};
25228       this.$$listenerCount = {};
25229       this.$$watchersCount = 0;
25230       this.$$isolateBindings = null;
25231     }
25232
25233     /**
25234      * @ngdoc property
25235      * @name $rootScope.Scope#$id
25236      *
25237      * @description
25238      * Unique scope ID (monotonically increasing) useful for debugging.
25239      */
25240
25241      /**
25242       * @ngdoc property
25243       * @name $rootScope.Scope#$parent
25244       *
25245       * @description
25246       * Reference to the parent scope.
25247       */
25248
25249       /**
25250        * @ngdoc property
25251        * @name $rootScope.Scope#$root
25252        *
25253        * @description
25254        * Reference to the root scope.
25255        */
25256
25257     Scope.prototype = {
25258       constructor: Scope,
25259       /**
25260        * @ngdoc method
25261        * @name $rootScope.Scope#$new
25262        * @kind function
25263        *
25264        * @description
25265        * Creates a new child {@link ng.$rootScope.Scope scope}.
25266        *
25267        * The parent scope will propagate the {@link ng.$rootScope.Scope#$digest $digest()} event.
25268        * The scope can be removed from the scope hierarchy using {@link ng.$rootScope.Scope#$destroy $destroy()}.
25269        *
25270        * {@link ng.$rootScope.Scope#$destroy $destroy()} must be called on a scope when it is
25271        * desired for the scope and its child scopes to be permanently detached from the parent and
25272        * thus stop participating in model change detection and listener notification by invoking.
25273        *
25274        * @param {boolean} isolate If true, then the scope does not prototypically inherit from the
25275        *         parent scope. The scope is isolated, as it can not see parent scope properties.
25276        *         When creating widgets, it is useful for the widget to not accidentally read parent
25277        *         state.
25278        *
25279        * @param {Scope} [parent=this] The {@link ng.$rootScope.Scope `Scope`} that will be the `$parent`
25280        *                              of the newly created scope. Defaults to `this` scope if not provided.
25281        *                              This is used when creating a transclude scope to correctly place it
25282        *                              in the scope hierarchy while maintaining the correct prototypical
25283        *                              inheritance.
25284        *
25285        * @returns {Object} The newly created child scope.
25286        *
25287        */
25288       $new: function(isolate, parent) {
25289         var child;
25290
25291         parent = parent || this;
25292
25293         if (isolate) {
25294           child = new Scope();
25295           child.$root = this.$root;
25296         } else {
25297           // Only create a child scope class if somebody asks for one,
25298           // but cache it to allow the VM to optimize lookups.
25299           if (!this.$$ChildScope) {
25300             this.$$ChildScope = createChildScopeClass(this);
25301           }
25302           child = new this.$$ChildScope();
25303         }
25304         child.$parent = parent;
25305         child.$$prevSibling = parent.$$childTail;
25306         if (parent.$$childHead) {
25307           parent.$$childTail.$$nextSibling = child;
25308           parent.$$childTail = child;
25309         } else {
25310           parent.$$childHead = parent.$$childTail = child;
25311         }
25312
25313         // When the new scope is not isolated or we inherit from `this`, and
25314         // the parent scope is destroyed, the property `$$destroyed` is inherited
25315         // prototypically. In all other cases, this property needs to be set
25316         // when the parent scope is destroyed.
25317         // The listener needs to be added after the parent is set
25318         if (isolate || parent != this) child.$on('$destroy', destroyChildScope);
25319
25320         return child;
25321       },
25322
25323       /**
25324        * @ngdoc method
25325        * @name $rootScope.Scope#$watch
25326        * @kind function
25327        *
25328        * @description
25329        * Registers a `listener` callback to be executed whenever the `watchExpression` changes.
25330        *
25331        * - The `watchExpression` is called on every call to {@link ng.$rootScope.Scope#$digest
25332        *   $digest()} and should return the value that will be watched. (`watchExpression` should not change
25333        *   its value when executed multiple times with the same input because it may be executed multiple
25334        *   times by {@link ng.$rootScope.Scope#$digest $digest()}. That is, `watchExpression` should be
25335        *   [idempotent](http://en.wikipedia.org/wiki/Idempotence).
25336        * - The `listener` is called only when the value from the current `watchExpression` and the
25337        *   previous call to `watchExpression` are not equal (with the exception of the initial run,
25338        *   see below). Inequality is determined according to reference inequality,
25339        *   [strict comparison](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Comparison_Operators)
25340        *    via the `!==` Javascript operator, unless `objectEquality == true`
25341        *   (see next point)
25342        * - When `objectEquality == true`, inequality of the `watchExpression` is determined
25343        *   according to the {@link angular.equals} function. To save the value of the object for
25344        *   later comparison, the {@link angular.copy} function is used. This therefore means that
25345        *   watching complex objects will have adverse memory and performance implications.
25346        * - The watch `listener` may change the model, which may trigger other `listener`s to fire.
25347        *   This is achieved by rerunning the watchers until no changes are detected. The rerun
25348        *   iteration limit is 10 to prevent an infinite loop deadlock.
25349        *
25350        *
25351        * If you want to be notified whenever {@link ng.$rootScope.Scope#$digest $digest} is called,
25352        * you can register a `watchExpression` function with no `listener`. (Be prepared for
25353        * multiple calls to your `watchExpression` because it will execute multiple times in a
25354        * single {@link ng.$rootScope.Scope#$digest $digest} cycle if a change is detected.)
25355        *
25356        * After a watcher is registered with the scope, the `listener` fn is called asynchronously
25357        * (via {@link ng.$rootScope.Scope#$evalAsync $evalAsync}) to initialize the
25358        * watcher. In rare cases, this is undesirable because the listener is called when the result
25359        * of `watchExpression` didn't change. To detect this scenario within the `listener` fn, you
25360        * can compare the `newVal` and `oldVal`. If these two values are identical (`===`) then the
25361        * listener was called due to initialization.
25362        *
25363        *
25364        *
25365        * # Example
25366        * ```js
25367            // let's assume that scope was dependency injected as the $rootScope
25368            var scope = $rootScope;
25369            scope.name = 'misko';
25370            scope.counter = 0;
25371
25372            expect(scope.counter).toEqual(0);
25373            scope.$watch('name', function(newValue, oldValue) {
25374              scope.counter = scope.counter + 1;
25375            });
25376            expect(scope.counter).toEqual(0);
25377
25378            scope.$digest();
25379            // the listener is always called during the first $digest loop after it was registered
25380            expect(scope.counter).toEqual(1);
25381
25382            scope.$digest();
25383            // but now it will not be called unless the value changes
25384            expect(scope.counter).toEqual(1);
25385
25386            scope.name = 'adam';
25387            scope.$digest();
25388            expect(scope.counter).toEqual(2);
25389
25390
25391
25392            // Using a function as a watchExpression
25393            var food;
25394            scope.foodCounter = 0;
25395            expect(scope.foodCounter).toEqual(0);
25396            scope.$watch(
25397              // This function returns the value being watched. It is called for each turn of the $digest loop
25398              function() { return food; },
25399              // This is the change listener, called when the value returned from the above function changes
25400              function(newValue, oldValue) {
25401                if ( newValue !== oldValue ) {
25402                  // Only increment the counter if the value changed
25403                  scope.foodCounter = scope.foodCounter + 1;
25404                }
25405              }
25406            );
25407            // No digest has been run so the counter will be zero
25408            expect(scope.foodCounter).toEqual(0);
25409
25410            // Run the digest but since food has not changed count will still be zero
25411            scope.$digest();
25412            expect(scope.foodCounter).toEqual(0);
25413
25414            // Update food and run digest.  Now the counter will increment
25415            food = 'cheeseburger';
25416            scope.$digest();
25417            expect(scope.foodCounter).toEqual(1);
25418
25419        * ```
25420        *
25421        *
25422        *
25423        * @param {(function()|string)} watchExpression Expression that is evaluated on each
25424        *    {@link ng.$rootScope.Scope#$digest $digest} cycle. A change in the return value triggers
25425        *    a call to the `listener`.
25426        *
25427        *    - `string`: Evaluated as {@link guide/expression expression}
25428        *    - `function(scope)`: called with current `scope` as a parameter.
25429        * @param {function(newVal, oldVal, scope)} listener Callback called whenever the value
25430        *    of `watchExpression` changes.
25431        *
25432        *    - `newVal` contains the current value of the `watchExpression`
25433        *    - `oldVal` contains the previous value of the `watchExpression`
25434        *    - `scope` refers to the current scope
25435        * @param {boolean=} [objectEquality=false] Compare for object equality using {@link angular.equals} instead of
25436        *     comparing for reference equality.
25437        * @returns {function()} Returns a deregistration function for this listener.
25438        */
25439       $watch: function(watchExp, listener, objectEquality, prettyPrintExpression) {
25440         var get = $parse(watchExp);
25441
25442         if (get.$$watchDelegate) {
25443           return get.$$watchDelegate(this, listener, objectEquality, get, watchExp);
25444         }
25445         var scope = this,
25446             array = scope.$$watchers,
25447             watcher = {
25448               fn: listener,
25449               last: initWatchVal,
25450               get: get,
25451               exp: prettyPrintExpression || watchExp,
25452               eq: !!objectEquality
25453             };
25454
25455         lastDirtyWatch = null;
25456
25457         if (!isFunction(listener)) {
25458           watcher.fn = noop;
25459         }
25460
25461         if (!array) {
25462           array = scope.$$watchers = [];
25463         }
25464         // we use unshift since we use a while loop in $digest for speed.
25465         // the while loop reads in reverse order.
25466         array.unshift(watcher);
25467         incrementWatchersCount(this, 1);
25468
25469         return function deregisterWatch() {
25470           if (arrayRemove(array, watcher) >= 0) {
25471             incrementWatchersCount(scope, -1);
25472           }
25473           lastDirtyWatch = null;
25474         };
25475       },
25476
25477       /**
25478        * @ngdoc method
25479        * @name $rootScope.Scope#$watchGroup
25480        * @kind function
25481        *
25482        * @description
25483        * A variant of {@link ng.$rootScope.Scope#$watch $watch()} where it watches an array of `watchExpressions`.
25484        * If any one expression in the collection changes the `listener` is executed.
25485        *
25486        * - The items in the `watchExpressions` array are observed via standard $watch operation and are examined on every
25487        *   call to $digest() to see if any items changes.
25488        * - The `listener` is called whenever any expression in the `watchExpressions` array changes.
25489        *
25490        * @param {Array.<string|Function(scope)>} watchExpressions Array of expressions that will be individually
25491        * watched using {@link ng.$rootScope.Scope#$watch $watch()}
25492        *
25493        * @param {function(newValues, oldValues, scope)} listener Callback called whenever the return value of any
25494        *    expression in `watchExpressions` changes
25495        *    The `newValues` array contains the current values of the `watchExpressions`, with the indexes matching
25496        *    those of `watchExpression`
25497        *    and the `oldValues` array contains the previous values of the `watchExpressions`, with the indexes matching
25498        *    those of `watchExpression`
25499        *    The `scope` refers to the current scope.
25500        * @returns {function()} Returns a de-registration function for all listeners.
25501        */
25502       $watchGroup: function(watchExpressions, listener) {
25503         var oldValues = new Array(watchExpressions.length);
25504         var newValues = new Array(watchExpressions.length);
25505         var deregisterFns = [];
25506         var self = this;
25507         var changeReactionScheduled = false;
25508         var firstRun = true;
25509
25510         if (!watchExpressions.length) {
25511           // No expressions means we call the listener ASAP
25512           var shouldCall = true;
25513           self.$evalAsync(function() {
25514             if (shouldCall) listener(newValues, newValues, self);
25515           });
25516           return function deregisterWatchGroup() {
25517             shouldCall = false;
25518           };
25519         }
25520
25521         if (watchExpressions.length === 1) {
25522           // Special case size of one
25523           return this.$watch(watchExpressions[0], function watchGroupAction(value, oldValue, scope) {
25524             newValues[0] = value;
25525             oldValues[0] = oldValue;
25526             listener(newValues, (value === oldValue) ? newValues : oldValues, scope);
25527           });
25528         }
25529
25530         forEach(watchExpressions, function(expr, i) {
25531           var unwatchFn = self.$watch(expr, function watchGroupSubAction(value, oldValue) {
25532             newValues[i] = value;
25533             oldValues[i] = oldValue;
25534             if (!changeReactionScheduled) {
25535               changeReactionScheduled = true;
25536               self.$evalAsync(watchGroupAction);
25537             }
25538           });
25539           deregisterFns.push(unwatchFn);
25540         });
25541
25542         function watchGroupAction() {
25543           changeReactionScheduled = false;
25544
25545           if (firstRun) {
25546             firstRun = false;
25547             listener(newValues, newValues, self);
25548           } else {
25549             listener(newValues, oldValues, self);
25550           }
25551         }
25552
25553         return function deregisterWatchGroup() {
25554           while (deregisterFns.length) {
25555             deregisterFns.shift()();
25556           }
25557         };
25558       },
25559
25560
25561       /**
25562        * @ngdoc method
25563        * @name $rootScope.Scope#$watchCollection
25564        * @kind function
25565        *
25566        * @description
25567        * Shallow watches the properties of an object and fires whenever any of the properties change
25568        * (for arrays, this implies watching the array items; for object maps, this implies watching
25569        * the properties). If a change is detected, the `listener` callback is fired.
25570        *
25571        * - The `obj` collection is observed via standard $watch operation and is examined on every
25572        *   call to $digest() to see if any items have been added, removed, or moved.
25573        * - The `listener` is called whenever anything within the `obj` has changed. Examples include
25574        *   adding, removing, and moving items belonging to an object or array.
25575        *
25576        *
25577        * # Example
25578        * ```js
25579           $scope.names = ['igor', 'matias', 'misko', 'james'];
25580           $scope.dataCount = 4;
25581
25582           $scope.$watchCollection('names', function(newNames, oldNames) {
25583             $scope.dataCount = newNames.length;
25584           });
25585
25586           expect($scope.dataCount).toEqual(4);
25587           $scope.$digest();
25588
25589           //still at 4 ... no changes
25590           expect($scope.dataCount).toEqual(4);
25591
25592           $scope.names.pop();
25593           $scope.$digest();
25594
25595           //now there's been a change
25596           expect($scope.dataCount).toEqual(3);
25597        * ```
25598        *
25599        *
25600        * @param {string|function(scope)} obj Evaluated as {@link guide/expression expression}. The
25601        *    expression value should evaluate to an object or an array which is observed on each
25602        *    {@link ng.$rootScope.Scope#$digest $digest} cycle. Any shallow change within the
25603        *    collection will trigger a call to the `listener`.
25604        *
25605        * @param {function(newCollection, oldCollection, scope)} listener a callback function called
25606        *    when a change is detected.
25607        *    - The `newCollection` object is the newly modified data obtained from the `obj` expression
25608        *    - The `oldCollection` object is a copy of the former collection data.
25609        *      Due to performance considerations, the`oldCollection` value is computed only if the
25610        *      `listener` function declares two or more arguments.
25611        *    - The `scope` argument refers to the current scope.
25612        *
25613        * @returns {function()} Returns a de-registration function for this listener. When the
25614        *    de-registration function is executed, the internal watch operation is terminated.
25615        */
25616       $watchCollection: function(obj, listener) {
25617         $watchCollectionInterceptor.$stateful = true;
25618
25619         var self = this;
25620         // the current value, updated on each dirty-check run
25621         var newValue;
25622         // a shallow copy of the newValue from the last dirty-check run,
25623         // updated to match newValue during dirty-check run
25624         var oldValue;
25625         // a shallow copy of the newValue from when the last change happened
25626         var veryOldValue;
25627         // only track veryOldValue if the listener is asking for it
25628         var trackVeryOldValue = (listener.length > 1);
25629         var changeDetected = 0;
25630         var changeDetector = $parse(obj, $watchCollectionInterceptor);
25631         var internalArray = [];
25632         var internalObject = {};
25633         var initRun = true;
25634         var oldLength = 0;
25635
25636         function $watchCollectionInterceptor(_value) {
25637           newValue = _value;
25638           var newLength, key, bothNaN, newItem, oldItem;
25639
25640           // If the new value is undefined, then return undefined as the watch may be a one-time watch
25641           if (isUndefined(newValue)) return;
25642
25643           if (!isObject(newValue)) { // if primitive
25644             if (oldValue !== newValue) {
25645               oldValue = newValue;
25646               changeDetected++;
25647             }
25648           } else if (isArrayLike(newValue)) {
25649             if (oldValue !== internalArray) {
25650               // we are transitioning from something which was not an array into array.
25651               oldValue = internalArray;
25652               oldLength = oldValue.length = 0;
25653               changeDetected++;
25654             }
25655
25656             newLength = newValue.length;
25657
25658             if (oldLength !== newLength) {
25659               // if lengths do not match we need to trigger change notification
25660               changeDetected++;
25661               oldValue.length = oldLength = newLength;
25662             }
25663             // copy the items to oldValue and look for changes.
25664             for (var i = 0; i < newLength; i++) {
25665               oldItem = oldValue[i];
25666               newItem = newValue[i];
25667
25668               bothNaN = (oldItem !== oldItem) && (newItem !== newItem);
25669               if (!bothNaN && (oldItem !== newItem)) {
25670                 changeDetected++;
25671                 oldValue[i] = newItem;
25672               }
25673             }
25674           } else {
25675             if (oldValue !== internalObject) {
25676               // we are transitioning from something which was not an object into object.
25677               oldValue = internalObject = {};
25678               oldLength = 0;
25679               changeDetected++;
25680             }
25681             // copy the items to oldValue and look for changes.
25682             newLength = 0;
25683             for (key in newValue) {
25684               if (hasOwnProperty.call(newValue, key)) {
25685                 newLength++;
25686                 newItem = newValue[key];
25687                 oldItem = oldValue[key];
25688
25689                 if (key in oldValue) {
25690                   bothNaN = (oldItem !== oldItem) && (newItem !== newItem);
25691                   if (!bothNaN && (oldItem !== newItem)) {
25692                     changeDetected++;
25693                     oldValue[key] = newItem;
25694                   }
25695                 } else {
25696                   oldLength++;
25697                   oldValue[key] = newItem;
25698                   changeDetected++;
25699                 }
25700               }
25701             }
25702             if (oldLength > newLength) {
25703               // we used to have more keys, need to find them and destroy them.
25704               changeDetected++;
25705               for (key in oldValue) {
25706                 if (!hasOwnProperty.call(newValue, key)) {
25707                   oldLength--;
25708                   delete oldValue[key];
25709                 }
25710               }
25711             }
25712           }
25713           return changeDetected;
25714         }
25715
25716         function $watchCollectionAction() {
25717           if (initRun) {
25718             initRun = false;
25719             listener(newValue, newValue, self);
25720           } else {
25721             listener(newValue, veryOldValue, self);
25722           }
25723
25724           // make a copy for the next time a collection is changed
25725           if (trackVeryOldValue) {
25726             if (!isObject(newValue)) {
25727               //primitive
25728               veryOldValue = newValue;
25729             } else if (isArrayLike(newValue)) {
25730               veryOldValue = new Array(newValue.length);
25731               for (var i = 0; i < newValue.length; i++) {
25732                 veryOldValue[i] = newValue[i];
25733               }
25734             } else { // if object
25735               veryOldValue = {};
25736               for (var key in newValue) {
25737                 if (hasOwnProperty.call(newValue, key)) {
25738                   veryOldValue[key] = newValue[key];
25739                 }
25740               }
25741             }
25742           }
25743         }
25744
25745         return this.$watch(changeDetector, $watchCollectionAction);
25746       },
25747
25748       /**
25749        * @ngdoc method
25750        * @name $rootScope.Scope#$digest
25751        * @kind function
25752        *
25753        * @description
25754        * Processes all of the {@link ng.$rootScope.Scope#$watch watchers} of the current scope and
25755        * its children. Because a {@link ng.$rootScope.Scope#$watch watcher}'s listener can change
25756        * the model, the `$digest()` keeps calling the {@link ng.$rootScope.Scope#$watch watchers}
25757        * until no more listeners are firing. This means that it is possible to get into an infinite
25758        * loop. This function will throw `'Maximum iteration limit exceeded.'` if the number of
25759        * iterations exceeds 10.
25760        *
25761        * Usually, you don't call `$digest()` directly in
25762        * {@link ng.directive:ngController controllers} or in
25763        * {@link ng.$compileProvider#directive directives}.
25764        * Instead, you should call {@link ng.$rootScope.Scope#$apply $apply()} (typically from within
25765        * a {@link ng.$compileProvider#directive directive}), which will force a `$digest()`.
25766        *
25767        * If you want to be notified whenever `$digest()` is called,
25768        * you can register a `watchExpression` function with
25769        * {@link ng.$rootScope.Scope#$watch $watch()} with no `listener`.
25770        *
25771        * In unit tests, you may need to call `$digest()` to simulate the scope life cycle.
25772        *
25773        * # Example
25774        * ```js
25775            var scope = ...;
25776            scope.name = 'misko';
25777            scope.counter = 0;
25778
25779            expect(scope.counter).toEqual(0);
25780            scope.$watch('name', function(newValue, oldValue) {
25781              scope.counter = scope.counter + 1;
25782            });
25783            expect(scope.counter).toEqual(0);
25784
25785            scope.$digest();
25786            // the listener is always called during the first $digest loop after it was registered
25787            expect(scope.counter).toEqual(1);
25788
25789            scope.$digest();
25790            // but now it will not be called unless the value changes
25791            expect(scope.counter).toEqual(1);
25792
25793            scope.name = 'adam';
25794            scope.$digest();
25795            expect(scope.counter).toEqual(2);
25796        * ```
25797        *
25798        */
25799       $digest: function() {
25800         var watch, value, last, fn, get,
25801             watchers,
25802             length,
25803             dirty, ttl = TTL,
25804             next, current, target = this,
25805             watchLog = [],
25806             logIdx, logMsg, asyncTask;
25807
25808         beginPhase('$digest');
25809         // Check for changes to browser url that happened in sync before the call to $digest
25810         $browser.$$checkUrlChange();
25811
25812         if (this === $rootScope && applyAsyncId !== null) {
25813           // If this is the root scope, and $applyAsync has scheduled a deferred $apply(), then
25814           // cancel the scheduled $apply and flush the queue of expressions to be evaluated.
25815           $browser.defer.cancel(applyAsyncId);
25816           flushApplyAsync();
25817         }
25818
25819         lastDirtyWatch = null;
25820
25821         do { // "while dirty" loop
25822           dirty = false;
25823           current = target;
25824
25825           while (asyncQueue.length) {
25826             try {
25827               asyncTask = asyncQueue.shift();
25828               asyncTask.scope.$eval(asyncTask.expression, asyncTask.locals);
25829             } catch (e) {
25830               $exceptionHandler(e);
25831             }
25832             lastDirtyWatch = null;
25833           }
25834
25835           traverseScopesLoop:
25836           do { // "traverse the scopes" loop
25837             if ((watchers = current.$$watchers)) {
25838               // process our watches
25839               length = watchers.length;
25840               while (length--) {
25841                 try {
25842                   watch = watchers[length];
25843                   // Most common watches are on primitives, in which case we can short
25844                   // circuit it with === operator, only when === fails do we use .equals
25845                   if (watch) {
25846                     get = watch.get;
25847                     if ((value = get(current)) !== (last = watch.last) &&
25848                         !(watch.eq
25849                             ? equals(value, last)
25850                             : (typeof value === 'number' && typeof last === 'number'
25851                                && isNaN(value) && isNaN(last)))) {
25852                       dirty = true;
25853                       lastDirtyWatch = watch;
25854                       watch.last = watch.eq ? copy(value, null) : value;
25855                       fn = watch.fn;
25856                       fn(value, ((last === initWatchVal) ? value : last), current);
25857                       if (ttl < 5) {
25858                         logIdx = 4 - ttl;
25859                         if (!watchLog[logIdx]) watchLog[logIdx] = [];
25860                         watchLog[logIdx].push({
25861                           msg: isFunction(watch.exp) ? 'fn: ' + (watch.exp.name || watch.exp.toString()) : watch.exp,
25862                           newVal: value,
25863                           oldVal: last
25864                         });
25865                       }
25866                     } else if (watch === lastDirtyWatch) {
25867                       // If the most recently dirty watcher is now clean, short circuit since the remaining watchers
25868                       // have already been tested.
25869                       dirty = false;
25870                       break traverseScopesLoop;
25871                     }
25872                   }
25873                 } catch (e) {
25874                   $exceptionHandler(e);
25875                 }
25876               }
25877             }
25878
25879             // Insanity Warning: scope depth-first traversal
25880             // yes, this code is a bit crazy, but it works and we have tests to prove it!
25881             // this piece should be kept in sync with the traversal in $broadcast
25882             if (!(next = ((current.$$watchersCount && current.$$childHead) ||
25883                 (current !== target && current.$$nextSibling)))) {
25884               while (current !== target && !(next = current.$$nextSibling)) {
25885                 current = current.$parent;
25886               }
25887             }
25888           } while ((current = next));
25889
25890           // `break traverseScopesLoop;` takes us to here
25891
25892           if ((dirty || asyncQueue.length) && !(ttl--)) {
25893             clearPhase();
25894             throw $rootScopeMinErr('infdig',
25895                 '{0} $digest() iterations reached. Aborting!\n' +
25896                 'Watchers fired in the last 5 iterations: {1}',
25897                 TTL, watchLog);
25898           }
25899
25900         } while (dirty || asyncQueue.length);
25901
25902         clearPhase();
25903
25904         while (postDigestQueue.length) {
25905           try {
25906             postDigestQueue.shift()();
25907           } catch (e) {
25908             $exceptionHandler(e);
25909           }
25910         }
25911       },
25912
25913
25914       /**
25915        * @ngdoc event
25916        * @name $rootScope.Scope#$destroy
25917        * @eventType broadcast on scope being destroyed
25918        *
25919        * @description
25920        * Broadcasted when a scope and its children are being destroyed.
25921        *
25922        * Note that, in AngularJS, there is also a `$destroy` jQuery event, which can be used to
25923        * clean up DOM bindings before an element is removed from the DOM.
25924        */
25925
25926       /**
25927        * @ngdoc method
25928        * @name $rootScope.Scope#$destroy
25929        * @kind function
25930        *
25931        * @description
25932        * Removes the current scope (and all of its children) from the parent scope. Removal implies
25933        * that calls to {@link ng.$rootScope.Scope#$digest $digest()} will no longer
25934        * propagate to the current scope and its children. Removal also implies that the current
25935        * scope is eligible for garbage collection.
25936        *
25937        * The `$destroy()` is usually used by directives such as
25938        * {@link ng.directive:ngRepeat ngRepeat} for managing the
25939        * unrolling of the loop.
25940        *
25941        * Just before a scope is destroyed, a `$destroy` event is broadcasted on this scope.
25942        * Application code can register a `$destroy` event handler that will give it a chance to
25943        * perform any necessary cleanup.
25944        *
25945        * Note that, in AngularJS, there is also a `$destroy` jQuery event, which can be used to
25946        * clean up DOM bindings before an element is removed from the DOM.
25947        */
25948       $destroy: function() {
25949         // We can't destroy a scope that has been already destroyed.
25950         if (this.$$destroyed) return;
25951         var parent = this.$parent;
25952
25953         this.$broadcast('$destroy');
25954         this.$$destroyed = true;
25955
25956         if (this === $rootScope) {
25957           //Remove handlers attached to window when $rootScope is removed
25958           $browser.$$applicationDestroyed();
25959         }
25960
25961         incrementWatchersCount(this, -this.$$watchersCount);
25962         for (var eventName in this.$$listenerCount) {
25963           decrementListenerCount(this, this.$$listenerCount[eventName], eventName);
25964         }
25965
25966         // sever all the references to parent scopes (after this cleanup, the current scope should
25967         // not be retained by any of our references and should be eligible for garbage collection)
25968         if (parent && parent.$$childHead == this) parent.$$childHead = this.$$nextSibling;
25969         if (parent && parent.$$childTail == this) parent.$$childTail = this.$$prevSibling;
25970         if (this.$$prevSibling) this.$$prevSibling.$$nextSibling = this.$$nextSibling;
25971         if (this.$$nextSibling) this.$$nextSibling.$$prevSibling = this.$$prevSibling;
25972
25973         // Disable listeners, watchers and apply/digest methods
25974         this.$destroy = this.$digest = this.$apply = this.$evalAsync = this.$applyAsync = noop;
25975         this.$on = this.$watch = this.$watchGroup = function() { return noop; };
25976         this.$$listeners = {};
25977
25978         // Disconnect the next sibling to prevent `cleanUpScope` destroying those too
25979         this.$$nextSibling = null;
25980         cleanUpScope(this);
25981       },
25982
25983       /**
25984        * @ngdoc method
25985        * @name $rootScope.Scope#$eval
25986        * @kind function
25987        *
25988        * @description
25989        * Executes the `expression` on the current scope and returns the result. Any exceptions in
25990        * the expression are propagated (uncaught). This is useful when evaluating Angular
25991        * expressions.
25992        *
25993        * # Example
25994        * ```js
25995            var scope = ng.$rootScope.Scope();
25996            scope.a = 1;
25997            scope.b = 2;
25998
25999            expect(scope.$eval('a+b')).toEqual(3);
26000            expect(scope.$eval(function(scope){ return scope.a + scope.b; })).toEqual(3);
26001        * ```
26002        *
26003        * @param {(string|function())=} expression An angular expression to be executed.
26004        *
26005        *    - `string`: execute using the rules as defined in  {@link guide/expression expression}.
26006        *    - `function(scope)`: execute the function with the current `scope` parameter.
26007        *
26008        * @param {(object)=} locals Local variables object, useful for overriding values in scope.
26009        * @returns {*} The result of evaluating the expression.
26010        */
26011       $eval: function(expr, locals) {
26012         return $parse(expr)(this, locals);
26013       },
26014
26015       /**
26016        * @ngdoc method
26017        * @name $rootScope.Scope#$evalAsync
26018        * @kind function
26019        *
26020        * @description
26021        * Executes the expression on the current scope at a later point in time.
26022        *
26023        * The `$evalAsync` makes no guarantees as to when the `expression` will be executed, only
26024        * that:
26025        *
26026        *   - it will execute after the function that scheduled the evaluation (preferably before DOM
26027        *     rendering).
26028        *   - at least one {@link ng.$rootScope.Scope#$digest $digest cycle} will be performed after
26029        *     `expression` execution.
26030        *
26031        * Any exceptions from the execution of the expression are forwarded to the
26032        * {@link ng.$exceptionHandler $exceptionHandler} service.
26033        *
26034        * __Note:__ if this function is called outside of a `$digest` cycle, a new `$digest` cycle
26035        * will be scheduled. However, it is encouraged to always call code that changes the model
26036        * from within an `$apply` call. That includes code evaluated via `$evalAsync`.
26037        *
26038        * @param {(string|function())=} expression An angular expression to be executed.
26039        *
26040        *    - `string`: execute using the rules as defined in {@link guide/expression expression}.
26041        *    - `function(scope)`: execute the function with the current `scope` parameter.
26042        *
26043        * @param {(object)=} locals Local variables object, useful for overriding values in scope.
26044        */
26045       $evalAsync: function(expr, locals) {
26046         // if we are outside of an $digest loop and this is the first time we are scheduling async
26047         // task also schedule async auto-flush
26048         if (!$rootScope.$$phase && !asyncQueue.length) {
26049           $browser.defer(function() {
26050             if (asyncQueue.length) {
26051               $rootScope.$digest();
26052             }
26053           });
26054         }
26055
26056         asyncQueue.push({scope: this, expression: $parse(expr), locals: locals});
26057       },
26058
26059       $$postDigest: function(fn) {
26060         postDigestQueue.push(fn);
26061       },
26062
26063       /**
26064        * @ngdoc method
26065        * @name $rootScope.Scope#$apply
26066        * @kind function
26067        *
26068        * @description
26069        * `$apply()` is used to execute an expression in angular from outside of the angular
26070        * framework. (For example from browser DOM events, setTimeout, XHR or third party libraries).
26071        * Because we are calling into the angular framework we need to perform proper scope life
26072        * cycle of {@link ng.$exceptionHandler exception handling},
26073        * {@link ng.$rootScope.Scope#$digest executing watches}.
26074        *
26075        * ## Life cycle
26076        *
26077        * # Pseudo-Code of `$apply()`
26078        * ```js
26079            function $apply(expr) {
26080              try {
26081                return $eval(expr);
26082              } catch (e) {
26083                $exceptionHandler(e);
26084              } finally {
26085                $root.$digest();
26086              }
26087            }
26088        * ```
26089        *
26090        *
26091        * Scope's `$apply()` method transitions through the following stages:
26092        *
26093        * 1. The {@link guide/expression expression} is executed using the
26094        *    {@link ng.$rootScope.Scope#$eval $eval()} method.
26095        * 2. Any exceptions from the execution of the expression are forwarded to the
26096        *    {@link ng.$exceptionHandler $exceptionHandler} service.
26097        * 3. The {@link ng.$rootScope.Scope#$watch watch} listeners are fired immediately after the
26098        *    expression was executed using the {@link ng.$rootScope.Scope#$digest $digest()} method.
26099        *
26100        *
26101        * @param {(string|function())=} exp An angular expression to be executed.
26102        *
26103        *    - `string`: execute using the rules as defined in {@link guide/expression expression}.
26104        *    - `function(scope)`: execute the function with current `scope` parameter.
26105        *
26106        * @returns {*} The result of evaluating the expression.
26107        */
26108       $apply: function(expr) {
26109         try {
26110           beginPhase('$apply');
26111           try {
26112             return this.$eval(expr);
26113           } finally {
26114             clearPhase();
26115           }
26116         } catch (e) {
26117           $exceptionHandler(e);
26118         } finally {
26119           try {
26120             $rootScope.$digest();
26121           } catch (e) {
26122             $exceptionHandler(e);
26123             throw e;
26124           }
26125         }
26126       },
26127
26128       /**
26129        * @ngdoc method
26130        * @name $rootScope.Scope#$applyAsync
26131        * @kind function
26132        *
26133        * @description
26134        * Schedule the invocation of $apply to occur at a later time. The actual time difference
26135        * varies across browsers, but is typically around ~10 milliseconds.
26136        *
26137        * This can be used to queue up multiple expressions which need to be evaluated in the same
26138        * digest.
26139        *
26140        * @param {(string|function())=} exp An angular expression to be executed.
26141        *
26142        *    - `string`: execute using the rules as defined in {@link guide/expression expression}.
26143        *    - `function(scope)`: execute the function with current `scope` parameter.
26144        */
26145       $applyAsync: function(expr) {
26146         var scope = this;
26147         expr && applyAsyncQueue.push($applyAsyncExpression);
26148         expr = $parse(expr);
26149         scheduleApplyAsync();
26150
26151         function $applyAsyncExpression() {
26152           scope.$eval(expr);
26153         }
26154       },
26155
26156       /**
26157        * @ngdoc method
26158        * @name $rootScope.Scope#$on
26159        * @kind function
26160        *
26161        * @description
26162        * Listens on events of a given type. See {@link ng.$rootScope.Scope#$emit $emit} for
26163        * discussion of event life cycle.
26164        *
26165        * The event listener function format is: `function(event, args...)`. The `event` object
26166        * passed into the listener has the following attributes:
26167        *
26168        *   - `targetScope` - `{Scope}`: the scope on which the event was `$emit`-ed or
26169        *     `$broadcast`-ed.
26170        *   - `currentScope` - `{Scope}`: the scope that is currently handling the event. Once the
26171        *     event propagates through the scope hierarchy, this property is set to null.
26172        *   - `name` - `{string}`: name of the event.
26173        *   - `stopPropagation` - `{function=}`: calling `stopPropagation` function will cancel
26174        *     further event propagation (available only for events that were `$emit`-ed).
26175        *   - `preventDefault` - `{function}`: calling `preventDefault` sets `defaultPrevented` flag
26176        *     to true.
26177        *   - `defaultPrevented` - `{boolean}`: true if `preventDefault` was called.
26178        *
26179        * @param {string} name Event name to listen on.
26180        * @param {function(event, ...args)} listener Function to call when the event is emitted.
26181        * @returns {function()} Returns a deregistration function for this listener.
26182        */
26183       $on: function(name, listener) {
26184         var namedListeners = this.$$listeners[name];
26185         if (!namedListeners) {
26186           this.$$listeners[name] = namedListeners = [];
26187         }
26188         namedListeners.push(listener);
26189
26190         var current = this;
26191         do {
26192           if (!current.$$listenerCount[name]) {
26193             current.$$listenerCount[name] = 0;
26194           }
26195           current.$$listenerCount[name]++;
26196         } while ((current = current.$parent));
26197
26198         var self = this;
26199         return function() {
26200           var indexOfListener = namedListeners.indexOf(listener);
26201           if (indexOfListener !== -1) {
26202             namedListeners[indexOfListener] = null;
26203             decrementListenerCount(self, 1, name);
26204           }
26205         };
26206       },
26207
26208
26209       /**
26210        * @ngdoc method
26211        * @name $rootScope.Scope#$emit
26212        * @kind function
26213        *
26214        * @description
26215        * Dispatches an event `name` upwards through the scope hierarchy notifying the
26216        * registered {@link ng.$rootScope.Scope#$on} listeners.
26217        *
26218        * The event life cycle starts at the scope on which `$emit` was called. All
26219        * {@link ng.$rootScope.Scope#$on listeners} listening for `name` event on this scope get
26220        * notified. Afterwards, the event traverses upwards toward the root scope and calls all
26221        * registered listeners along the way. The event will stop propagating if one of the listeners
26222        * cancels it.
26223        *
26224        * Any exception emitted from the {@link ng.$rootScope.Scope#$on listeners} will be passed
26225        * onto the {@link ng.$exceptionHandler $exceptionHandler} service.
26226        *
26227        * @param {string} name Event name to emit.
26228        * @param {...*} args Optional one or more arguments which will be passed onto the event listeners.
26229        * @return {Object} Event object (see {@link ng.$rootScope.Scope#$on}).
26230        */
26231       $emit: function(name, args) {
26232         var empty = [],
26233             namedListeners,
26234             scope = this,
26235             stopPropagation = false,
26236             event = {
26237               name: name,
26238               targetScope: scope,
26239               stopPropagation: function() {stopPropagation = true;},
26240               preventDefault: function() {
26241                 event.defaultPrevented = true;
26242               },
26243               defaultPrevented: false
26244             },
26245             listenerArgs = concat([event], arguments, 1),
26246             i, length;
26247
26248         do {
26249           namedListeners = scope.$$listeners[name] || empty;
26250           event.currentScope = scope;
26251           for (i = 0, length = namedListeners.length; i < length; i++) {
26252
26253             // if listeners were deregistered, defragment the array
26254             if (!namedListeners[i]) {
26255               namedListeners.splice(i, 1);
26256               i--;
26257               length--;
26258               continue;
26259             }
26260             try {
26261               //allow all listeners attached to the current scope to run
26262               namedListeners[i].apply(null, listenerArgs);
26263             } catch (e) {
26264               $exceptionHandler(e);
26265             }
26266           }
26267           //if any listener on the current scope stops propagation, prevent bubbling
26268           if (stopPropagation) {
26269             event.currentScope = null;
26270             return event;
26271           }
26272           //traverse upwards
26273           scope = scope.$parent;
26274         } while (scope);
26275
26276         event.currentScope = null;
26277
26278         return event;
26279       },
26280
26281
26282       /**
26283        * @ngdoc method
26284        * @name $rootScope.Scope#$broadcast
26285        * @kind function
26286        *
26287        * @description
26288        * Dispatches an event `name` downwards to all child scopes (and their children) notifying the
26289        * registered {@link ng.$rootScope.Scope#$on} listeners.
26290        *
26291        * The event life cycle starts at the scope on which `$broadcast` was called. All
26292        * {@link ng.$rootScope.Scope#$on listeners} listening for `name` event on this scope get
26293        * notified. Afterwards, the event propagates to all direct and indirect scopes of the current
26294        * scope and calls all registered listeners along the way. The event cannot be canceled.
26295        *
26296        * Any exception emitted from the {@link ng.$rootScope.Scope#$on listeners} will be passed
26297        * onto the {@link ng.$exceptionHandler $exceptionHandler} service.
26298        *
26299        * @param {string} name Event name to broadcast.
26300        * @param {...*} args Optional one or more arguments which will be passed onto the event listeners.
26301        * @return {Object} Event object, see {@link ng.$rootScope.Scope#$on}
26302        */
26303       $broadcast: function(name, args) {
26304         var target = this,
26305             current = target,
26306             next = target,
26307             event = {
26308               name: name,
26309               targetScope: target,
26310               preventDefault: function() {
26311                 event.defaultPrevented = true;
26312               },
26313               defaultPrevented: false
26314             };
26315
26316         if (!target.$$listenerCount[name]) return event;
26317
26318         var listenerArgs = concat([event], arguments, 1),
26319             listeners, i, length;
26320
26321         //down while you can, then up and next sibling or up and next sibling until back at root
26322         while ((current = next)) {
26323           event.currentScope = current;
26324           listeners = current.$$listeners[name] || [];
26325           for (i = 0, length = listeners.length; i < length; i++) {
26326             // if listeners were deregistered, defragment the array
26327             if (!listeners[i]) {
26328               listeners.splice(i, 1);
26329               i--;
26330               length--;
26331               continue;
26332             }
26333
26334             try {
26335               listeners[i].apply(null, listenerArgs);
26336             } catch (e) {
26337               $exceptionHandler(e);
26338             }
26339           }
26340
26341           // Insanity Warning: scope depth-first traversal
26342           // yes, this code is a bit crazy, but it works and we have tests to prove it!
26343           // this piece should be kept in sync with the traversal in $digest
26344           // (though it differs due to having the extra check for $$listenerCount)
26345           if (!(next = ((current.$$listenerCount[name] && current.$$childHead) ||
26346               (current !== target && current.$$nextSibling)))) {
26347             while (current !== target && !(next = current.$$nextSibling)) {
26348               current = current.$parent;
26349             }
26350           }
26351         }
26352
26353         event.currentScope = null;
26354         return event;
26355       }
26356     };
26357
26358     var $rootScope = new Scope();
26359
26360     //The internal queues. Expose them on the $rootScope for debugging/testing purposes.
26361     var asyncQueue = $rootScope.$$asyncQueue = [];
26362     var postDigestQueue = $rootScope.$$postDigestQueue = [];
26363     var applyAsyncQueue = $rootScope.$$applyAsyncQueue = [];
26364
26365     return $rootScope;
26366
26367
26368     function beginPhase(phase) {
26369       if ($rootScope.$$phase) {
26370         throw $rootScopeMinErr('inprog', '{0} already in progress', $rootScope.$$phase);
26371       }
26372
26373       $rootScope.$$phase = phase;
26374     }
26375
26376     function clearPhase() {
26377       $rootScope.$$phase = null;
26378     }
26379
26380     function incrementWatchersCount(current, count) {
26381       do {
26382         current.$$watchersCount += count;
26383       } while ((current = current.$parent));
26384     }
26385
26386     function decrementListenerCount(current, count, name) {
26387       do {
26388         current.$$listenerCount[name] -= count;
26389
26390         if (current.$$listenerCount[name] === 0) {
26391           delete current.$$listenerCount[name];
26392         }
26393       } while ((current = current.$parent));
26394     }
26395
26396     /**
26397      * function used as an initial value for watchers.
26398      * because it's unique we can easily tell it apart from other values
26399      */
26400     function initWatchVal() {}
26401
26402     function flushApplyAsync() {
26403       while (applyAsyncQueue.length) {
26404         try {
26405           applyAsyncQueue.shift()();
26406         } catch (e) {
26407           $exceptionHandler(e);
26408         }
26409       }
26410       applyAsyncId = null;
26411     }
26412
26413     function scheduleApplyAsync() {
26414       if (applyAsyncId === null) {
26415         applyAsyncId = $browser.defer(function() {
26416           $rootScope.$apply(flushApplyAsync);
26417         });
26418       }
26419     }
26420   }];
26421 }
26422
26423 /**
26424  * @ngdoc service
26425  * @name $rootElement
26426  *
26427  * @description
26428  * The root element of Angular application. This is either the element where {@link
26429  * ng.directive:ngApp ngApp} was declared or the element passed into
26430  * {@link angular.bootstrap}. The element represents the root element of application. It is also the
26431  * location where the application's {@link auto.$injector $injector} service gets
26432  * published, and can be retrieved using `$rootElement.injector()`.
26433  */
26434
26435
26436 // the implementation is in angular.bootstrap
26437
26438 /**
26439  * @description
26440  * Private service to sanitize uris for links and images. Used by $compile and $sanitize.
26441  */
26442 function $$SanitizeUriProvider() {
26443   var aHrefSanitizationWhitelist = /^\s*(https?|ftp|mailto|tel|file):/,
26444     imgSrcSanitizationWhitelist = /^\s*((https?|ftp|file|blob):|data:image\/)/;
26445
26446   /**
26447    * @description
26448    * Retrieves or overrides the default regular expression that is used for whitelisting of safe
26449    * urls during a[href] sanitization.
26450    *
26451    * The sanitization is a security measure aimed at prevent XSS attacks via html links.
26452    *
26453    * Any url about to be assigned to a[href] via data-binding is first normalized and turned into
26454    * an absolute url. Afterwards, the url is matched against the `aHrefSanitizationWhitelist`
26455    * regular expression. If a match is found, the original url is written into the dom. Otherwise,
26456    * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM.
26457    *
26458    * @param {RegExp=} regexp New regexp to whitelist urls with.
26459    * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
26460    *    chaining otherwise.
26461    */
26462   this.aHrefSanitizationWhitelist = function(regexp) {
26463     if (isDefined(regexp)) {
26464       aHrefSanitizationWhitelist = regexp;
26465       return this;
26466     }
26467     return aHrefSanitizationWhitelist;
26468   };
26469
26470
26471   /**
26472    * @description
26473    * Retrieves or overrides the default regular expression that is used for whitelisting of safe
26474    * urls during img[src] sanitization.
26475    *
26476    * The sanitization is a security measure aimed at prevent XSS attacks via html links.
26477    *
26478    * Any url about to be assigned to img[src] via data-binding is first normalized and turned into
26479    * an absolute url. Afterwards, the url is matched against the `imgSrcSanitizationWhitelist`
26480    * regular expression. If a match is found, the original url is written into the dom. Otherwise,
26481    * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM.
26482    *
26483    * @param {RegExp=} regexp New regexp to whitelist urls with.
26484    * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
26485    *    chaining otherwise.
26486    */
26487   this.imgSrcSanitizationWhitelist = function(regexp) {
26488     if (isDefined(regexp)) {
26489       imgSrcSanitizationWhitelist = regexp;
26490       return this;
26491     }
26492     return imgSrcSanitizationWhitelist;
26493   };
26494
26495   this.$get = function() {
26496     return function sanitizeUri(uri, isImage) {
26497       var regex = isImage ? imgSrcSanitizationWhitelist : aHrefSanitizationWhitelist;
26498       var normalizedVal;
26499       normalizedVal = urlResolve(uri).href;
26500       if (normalizedVal !== '' && !normalizedVal.match(regex)) {
26501         return 'unsafe:' + normalizedVal;
26502       }
26503       return uri;
26504     };
26505   };
26506 }
26507
26508 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
26509  *     Any commits to this file should be reviewed with security in mind.  *
26510  *   Changes to this file can potentially create security vulnerabilities. *
26511  *          An approval from 2 Core members with history of modifying      *
26512  *                         this file is required.                          *
26513  *                                                                         *
26514  *  Does the change somehow allow for arbitrary javascript to be executed? *
26515  *    Or allows for someone to change the prototype of built-in objects?   *
26516  *     Or gives undesired access to variables likes document or window?    *
26517  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
26518
26519 var $sceMinErr = minErr('$sce');
26520
26521 var SCE_CONTEXTS = {
26522   HTML: 'html',
26523   CSS: 'css',
26524   URL: 'url',
26525   // RESOURCE_URL is a subtype of URL used in contexts where a privileged resource is sourced from a
26526   // url.  (e.g. ng-include, script src, templateUrl)
26527   RESOURCE_URL: 'resourceUrl',
26528   JS: 'js'
26529 };
26530
26531 // Helper functions follow.
26532
26533 function adjustMatcher(matcher) {
26534   if (matcher === 'self') {
26535     return matcher;
26536   } else if (isString(matcher)) {
26537     // Strings match exactly except for 2 wildcards - '*' and '**'.
26538     // '*' matches any character except those from the set ':/.?&'.
26539     // '**' matches any character (like .* in a RegExp).
26540     // More than 2 *'s raises an error as it's ill defined.
26541     if (matcher.indexOf('***') > -1) {
26542       throw $sceMinErr('iwcard',
26543           'Illegal sequence *** in string matcher.  String: {0}', matcher);
26544     }
26545     matcher = escapeForRegexp(matcher).
26546                   replace('\\*\\*', '.*').
26547                   replace('\\*', '[^:/.?&;]*');
26548     return new RegExp('^' + matcher + '$');
26549   } else if (isRegExp(matcher)) {
26550     // The only other type of matcher allowed is a Regexp.
26551     // Match entire URL / disallow partial matches.
26552     // Flags are reset (i.e. no global, ignoreCase or multiline)
26553     return new RegExp('^' + matcher.source + '$');
26554   } else {
26555     throw $sceMinErr('imatcher',
26556         'Matchers may only be "self", string patterns or RegExp objects');
26557   }
26558 }
26559
26560
26561 function adjustMatchers(matchers) {
26562   var adjustedMatchers = [];
26563   if (isDefined(matchers)) {
26564     forEach(matchers, function(matcher) {
26565       adjustedMatchers.push(adjustMatcher(matcher));
26566     });
26567   }
26568   return adjustedMatchers;
26569 }
26570
26571
26572 /**
26573  * @ngdoc service
26574  * @name $sceDelegate
26575  * @kind function
26576  *
26577  * @description
26578  *
26579  * `$sceDelegate` is a service that is used by the `$sce` service to provide {@link ng.$sce Strict
26580  * Contextual Escaping (SCE)} services to AngularJS.
26581  *
26582  * Typically, you would configure or override the {@link ng.$sceDelegate $sceDelegate} instead of
26583  * the `$sce` service to customize the way Strict Contextual Escaping works in AngularJS.  This is
26584  * because, while the `$sce` provides numerous shorthand methods, etc., you really only need to
26585  * override 3 core functions (`trustAs`, `getTrusted` and `valueOf`) to replace the way things
26586  * work because `$sce` delegates to `$sceDelegate` for these operations.
26587  *
26588  * Refer {@link ng.$sceDelegateProvider $sceDelegateProvider} to configure this service.
26589  *
26590  * The default instance of `$sceDelegate` should work out of the box with little pain.  While you
26591  * can override it completely to change the behavior of `$sce`, the common case would
26592  * involve configuring the {@link ng.$sceDelegateProvider $sceDelegateProvider} instead by setting
26593  * your own whitelists and blacklists for trusting URLs used for loading AngularJS resources such as
26594  * templates.  Refer {@link ng.$sceDelegateProvider#resourceUrlWhitelist
26595  * $sceDelegateProvider.resourceUrlWhitelist} and {@link
26596  * ng.$sceDelegateProvider#resourceUrlBlacklist $sceDelegateProvider.resourceUrlBlacklist}
26597  */
26598
26599 /**
26600  * @ngdoc provider
26601  * @name $sceDelegateProvider
26602  * @description
26603  *
26604  * The `$sceDelegateProvider` provider allows developers to configure the {@link ng.$sceDelegate
26605  * $sceDelegate} service.  This allows one to get/set the whitelists and blacklists used to ensure
26606  * that the URLs used for sourcing Angular templates are safe.  Refer {@link
26607  * ng.$sceDelegateProvider#resourceUrlWhitelist $sceDelegateProvider.resourceUrlWhitelist} and
26608  * {@link ng.$sceDelegateProvider#resourceUrlBlacklist $sceDelegateProvider.resourceUrlBlacklist}
26609  *
26610  * For the general details about this service in Angular, read the main page for {@link ng.$sce
26611  * Strict Contextual Escaping (SCE)}.
26612  *
26613  * **Example**:  Consider the following case. <a name="example"></a>
26614  *
26615  * - your app is hosted at url `http://myapp.example.com/`
26616  * - but some of your templates are hosted on other domains you control such as
26617  *   `http://srv01.assets.example.com/`,  `http://srv02.assets.example.com/`, etc.
26618  * - and you have an open redirect at `http://myapp.example.com/clickThru?...`.
26619  *
26620  * Here is what a secure configuration for this scenario might look like:
26621  *
26622  * ```
26623  *  angular.module('myApp', []).config(function($sceDelegateProvider) {
26624  *    $sceDelegateProvider.resourceUrlWhitelist([
26625  *      // Allow same origin resource loads.
26626  *      'self',
26627  *      // Allow loading from our assets domain.  Notice the difference between * and **.
26628  *      'http://srv*.assets.example.com/**'
26629  *    ]);
26630  *
26631  *    // The blacklist overrides the whitelist so the open redirect here is blocked.
26632  *    $sceDelegateProvider.resourceUrlBlacklist([
26633  *      'http://myapp.example.com/clickThru**'
26634  *    ]);
26635  *  });
26636  * ```
26637  */
26638
26639 function $SceDelegateProvider() {
26640   this.SCE_CONTEXTS = SCE_CONTEXTS;
26641
26642   // Resource URLs can also be trusted by policy.
26643   var resourceUrlWhitelist = ['self'],
26644       resourceUrlBlacklist = [];
26645
26646   /**
26647    * @ngdoc method
26648    * @name $sceDelegateProvider#resourceUrlWhitelist
26649    * @kind function
26650    *
26651    * @param {Array=} whitelist When provided, replaces the resourceUrlWhitelist with the value
26652    *    provided.  This must be an array or null.  A snapshot of this array is used so further
26653    *    changes to the array are ignored.
26654    *
26655    *    Follow {@link ng.$sce#resourceUrlPatternItem this link} for a description of the items
26656    *    allowed in this array.
26657    *
26658    *    <div class="alert alert-warning">
26659    *    **Note:** an empty whitelist array will block all URLs!
26660    *    </div>
26661    *
26662    * @return {Array} the currently set whitelist array.
26663    *
26664    * The **default value** when no whitelist has been explicitly set is `['self']` allowing only
26665    * same origin resource requests.
26666    *
26667    * @description
26668    * Sets/Gets the whitelist of trusted resource URLs.
26669    */
26670   this.resourceUrlWhitelist = function(value) {
26671     if (arguments.length) {
26672       resourceUrlWhitelist = adjustMatchers(value);
26673     }
26674     return resourceUrlWhitelist;
26675   };
26676
26677   /**
26678    * @ngdoc method
26679    * @name $sceDelegateProvider#resourceUrlBlacklist
26680    * @kind function
26681    *
26682    * @param {Array=} blacklist When provided, replaces the resourceUrlBlacklist with the value
26683    *    provided.  This must be an array or null.  A snapshot of this array is used so further
26684    *    changes to the array are ignored.
26685    *
26686    *    Follow {@link ng.$sce#resourceUrlPatternItem this link} for a description of the items
26687    *    allowed in this array.
26688    *
26689    *    The typical usage for the blacklist is to **block
26690    *    [open redirects](http://cwe.mitre.org/data/definitions/601.html)** served by your domain as
26691    *    these would otherwise be trusted but actually return content from the redirected domain.
26692    *
26693    *    Finally, **the blacklist overrides the whitelist** and has the final say.
26694    *
26695    * @return {Array} the currently set blacklist array.
26696    *
26697    * The **default value** when no whitelist has been explicitly set is the empty array (i.e. there
26698    * is no blacklist.)
26699    *
26700    * @description
26701    * Sets/Gets the blacklist of trusted resource URLs.
26702    */
26703
26704   this.resourceUrlBlacklist = function(value) {
26705     if (arguments.length) {
26706       resourceUrlBlacklist = adjustMatchers(value);
26707     }
26708     return resourceUrlBlacklist;
26709   };
26710
26711   this.$get = ['$injector', function($injector) {
26712
26713     var htmlSanitizer = function htmlSanitizer(html) {
26714       throw $sceMinErr('unsafe', 'Attempting to use an unsafe value in a safe context.');
26715     };
26716
26717     if ($injector.has('$sanitize')) {
26718       htmlSanitizer = $injector.get('$sanitize');
26719     }
26720
26721
26722     function matchUrl(matcher, parsedUrl) {
26723       if (matcher === 'self') {
26724         return urlIsSameOrigin(parsedUrl);
26725       } else {
26726         // definitely a regex.  See adjustMatchers()
26727         return !!matcher.exec(parsedUrl.href);
26728       }
26729     }
26730
26731     function isResourceUrlAllowedByPolicy(url) {
26732       var parsedUrl = urlResolve(url.toString());
26733       var i, n, allowed = false;
26734       // Ensure that at least one item from the whitelist allows this url.
26735       for (i = 0, n = resourceUrlWhitelist.length; i < n; i++) {
26736         if (matchUrl(resourceUrlWhitelist[i], parsedUrl)) {
26737           allowed = true;
26738           break;
26739         }
26740       }
26741       if (allowed) {
26742         // Ensure that no item from the blacklist blocked this url.
26743         for (i = 0, n = resourceUrlBlacklist.length; i < n; i++) {
26744           if (matchUrl(resourceUrlBlacklist[i], parsedUrl)) {
26745             allowed = false;
26746             break;
26747           }
26748         }
26749       }
26750       return allowed;
26751     }
26752
26753     function generateHolderType(Base) {
26754       var holderType = function TrustedValueHolderType(trustedValue) {
26755         this.$$unwrapTrustedValue = function() {
26756           return trustedValue;
26757         };
26758       };
26759       if (Base) {
26760         holderType.prototype = new Base();
26761       }
26762       holderType.prototype.valueOf = function sceValueOf() {
26763         return this.$$unwrapTrustedValue();
26764       };
26765       holderType.prototype.toString = function sceToString() {
26766         return this.$$unwrapTrustedValue().toString();
26767       };
26768       return holderType;
26769     }
26770
26771     var trustedValueHolderBase = generateHolderType(),
26772         byType = {};
26773
26774     byType[SCE_CONTEXTS.HTML] = generateHolderType(trustedValueHolderBase);
26775     byType[SCE_CONTEXTS.CSS] = generateHolderType(trustedValueHolderBase);
26776     byType[SCE_CONTEXTS.URL] = generateHolderType(trustedValueHolderBase);
26777     byType[SCE_CONTEXTS.JS] = generateHolderType(trustedValueHolderBase);
26778     byType[SCE_CONTEXTS.RESOURCE_URL] = generateHolderType(byType[SCE_CONTEXTS.URL]);
26779
26780     /**
26781      * @ngdoc method
26782      * @name $sceDelegate#trustAs
26783      *
26784      * @description
26785      * Returns an object that is trusted by angular for use in specified strict
26786      * contextual escaping contexts (such as ng-bind-html, ng-include, any src
26787      * attribute interpolation, any dom event binding attribute interpolation
26788      * such as for onclick,  etc.) that uses the provided value.
26789      * See {@link ng.$sce $sce} for enabling strict contextual escaping.
26790      *
26791      * @param {string} type The kind of context in which this value is safe for use.  e.g. url,
26792      *   resourceUrl, html, js and css.
26793      * @param {*} value The value that that should be considered trusted/safe.
26794      * @returns {*} A value that can be used to stand in for the provided `value` in places
26795      * where Angular expects a $sce.trustAs() return value.
26796      */
26797     function trustAs(type, trustedValue) {
26798       var Constructor = (byType.hasOwnProperty(type) ? byType[type] : null);
26799       if (!Constructor) {
26800         throw $sceMinErr('icontext',
26801             'Attempted to trust a value in invalid context. Context: {0}; Value: {1}',
26802             type, trustedValue);
26803       }
26804       if (trustedValue === null || isUndefined(trustedValue) || trustedValue === '') {
26805         return trustedValue;
26806       }
26807       // All the current contexts in SCE_CONTEXTS happen to be strings.  In order to avoid trusting
26808       // mutable objects, we ensure here that the value passed in is actually a string.
26809       if (typeof trustedValue !== 'string') {
26810         throw $sceMinErr('itype',
26811             'Attempted to trust a non-string value in a content requiring a string: Context: {0}',
26812             type);
26813       }
26814       return new Constructor(trustedValue);
26815     }
26816
26817     /**
26818      * @ngdoc method
26819      * @name $sceDelegate#valueOf
26820      *
26821      * @description
26822      * If the passed parameter had been returned by a prior call to {@link ng.$sceDelegate#trustAs
26823      * `$sceDelegate.trustAs`}, returns the value that had been passed to {@link
26824      * ng.$sceDelegate#trustAs `$sceDelegate.trustAs`}.
26825      *
26826      * If the passed parameter is not a value that had been returned by {@link
26827      * ng.$sceDelegate#trustAs `$sceDelegate.trustAs`}, returns it as-is.
26828      *
26829      * @param {*} value The result of a prior {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs`}
26830      *      call or anything else.
26831      * @returns {*} The `value` that was originally provided to {@link ng.$sceDelegate#trustAs
26832      *     `$sceDelegate.trustAs`} if `value` is the result of such a call.  Otherwise, returns
26833      *     `value` unchanged.
26834      */
26835     function valueOf(maybeTrusted) {
26836       if (maybeTrusted instanceof trustedValueHolderBase) {
26837         return maybeTrusted.$$unwrapTrustedValue();
26838       } else {
26839         return maybeTrusted;
26840       }
26841     }
26842
26843     /**
26844      * @ngdoc method
26845      * @name $sceDelegate#getTrusted
26846      *
26847      * @description
26848      * Takes the result of a {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs`} call and
26849      * returns the originally supplied value if the queried context type is a supertype of the
26850      * created type.  If this condition isn't satisfied, throws an exception.
26851      *
26852      * <div class="alert alert-danger">
26853      * Disabling auto-escaping is extremely dangerous, it usually creates a Cross Site Scripting
26854      * (XSS) vulnerability in your application.
26855      * </div>
26856      *
26857      * @param {string} type The kind of context in which this value is to be used.
26858      * @param {*} maybeTrusted The result of a prior {@link ng.$sceDelegate#trustAs
26859      *     `$sceDelegate.trustAs`} call.
26860      * @returns {*} The value the was originally provided to {@link ng.$sceDelegate#trustAs
26861      *     `$sceDelegate.trustAs`} if valid in this context.  Otherwise, throws an exception.
26862      */
26863     function getTrusted(type, maybeTrusted) {
26864       if (maybeTrusted === null || isUndefined(maybeTrusted) || maybeTrusted === '') {
26865         return maybeTrusted;
26866       }
26867       var constructor = (byType.hasOwnProperty(type) ? byType[type] : null);
26868       if (constructor && maybeTrusted instanceof constructor) {
26869         return maybeTrusted.$$unwrapTrustedValue();
26870       }
26871       // If we get here, then we may only take one of two actions.
26872       // 1. sanitize the value for the requested type, or
26873       // 2. throw an exception.
26874       if (type === SCE_CONTEXTS.RESOURCE_URL) {
26875         if (isResourceUrlAllowedByPolicy(maybeTrusted)) {
26876           return maybeTrusted;
26877         } else {
26878           throw $sceMinErr('insecurl',
26879               'Blocked loading resource from url not allowed by $sceDelegate policy.  URL: {0}',
26880               maybeTrusted.toString());
26881         }
26882       } else if (type === SCE_CONTEXTS.HTML) {
26883         return htmlSanitizer(maybeTrusted);
26884       }
26885       throw $sceMinErr('unsafe', 'Attempting to use an unsafe value in a safe context.');
26886     }
26887
26888     return { trustAs: trustAs,
26889              getTrusted: getTrusted,
26890              valueOf: valueOf };
26891   }];
26892 }
26893
26894
26895 /**
26896  * @ngdoc provider
26897  * @name $sceProvider
26898  * @description
26899  *
26900  * The $sceProvider provider allows developers to configure the {@link ng.$sce $sce} service.
26901  * -   enable/disable Strict Contextual Escaping (SCE) in a module
26902  * -   override the default implementation with a custom delegate
26903  *
26904  * Read more about {@link ng.$sce Strict Contextual Escaping (SCE)}.
26905  */
26906
26907 /* jshint maxlen: false*/
26908
26909 /**
26910  * @ngdoc service
26911  * @name $sce
26912  * @kind function
26913  *
26914  * @description
26915  *
26916  * `$sce` is a service that provides Strict Contextual Escaping services to AngularJS.
26917  *
26918  * # Strict Contextual Escaping
26919  *
26920  * Strict Contextual Escaping (SCE) is a mode in which AngularJS requires bindings in certain
26921  * contexts to result in a value that is marked as safe to use for that context.  One example of
26922  * such a context is binding arbitrary html controlled by the user via `ng-bind-html`.  We refer
26923  * to these contexts as privileged or SCE contexts.
26924  *
26925  * As of version 1.2, Angular ships with SCE enabled by default.
26926  *
26927  * Note:  When enabled (the default), IE<11 in quirks mode is not supported.  In this mode, IE<11 allow
26928  * one to execute arbitrary javascript by the use of the expression() syntax.  Refer
26929  * <http://blogs.msdn.com/b/ie/archive/2008/10/16/ending-expressions.aspx> to learn more about them.
26930  * You can ensure your document is in standards mode and not quirks mode by adding `<!doctype html>`
26931  * to the top of your HTML document.
26932  *
26933  * SCE assists in writing code in way that (a) is secure by default and (b) makes auditing for
26934  * security vulnerabilities such as XSS, clickjacking, etc. a lot easier.
26935  *
26936  * Here's an example of a binding in a privileged context:
26937  *
26938  * ```
26939  * <input ng-model="userHtml" aria-label="User input">
26940  * <div ng-bind-html="userHtml"></div>
26941  * ```
26942  *
26943  * Notice that `ng-bind-html` is bound to `userHtml` controlled by the user.  With SCE
26944  * disabled, this application allows the user to render arbitrary HTML into the DIV.
26945  * In a more realistic example, one may be rendering user comments, blog articles, etc. via
26946  * bindings.  (HTML is just one example of a context where rendering user controlled input creates
26947  * security vulnerabilities.)
26948  *
26949  * For the case of HTML, you might use a library, either on the client side, or on the server side,
26950  * to sanitize unsafe HTML before binding to the value and rendering it in the document.
26951  *
26952  * How would you ensure that every place that used these types of bindings was bound to a value that
26953  * was sanitized by your library (or returned as safe for rendering by your server?)  How can you
26954  * ensure that you didn't accidentally delete the line that sanitized the value, or renamed some
26955  * properties/fields and forgot to update the binding to the sanitized value?
26956  *
26957  * To be secure by default, you want to ensure that any such bindings are disallowed unless you can
26958  * determine that something explicitly says it's safe to use a value for binding in that
26959  * context.  You can then audit your code (a simple grep would do) to ensure that this is only done
26960  * for those values that you can easily tell are safe - because they were received from your server,
26961  * sanitized by your library, etc.  You can organize your codebase to help with this - perhaps
26962  * allowing only the files in a specific directory to do this.  Ensuring that the internal API
26963  * exposed by that code doesn't markup arbitrary values as safe then becomes a more manageable task.
26964  *
26965  * In the case of AngularJS' SCE service, one uses {@link ng.$sce#trustAs $sce.trustAs}
26966  * (and shorthand methods such as {@link ng.$sce#trustAsHtml $sce.trustAsHtml}, etc.) to
26967  * obtain values that will be accepted by SCE / privileged contexts.
26968  *
26969  *
26970  * ## How does it work?
26971  *
26972  * In privileged contexts, directives and code will bind to the result of {@link ng.$sce#getTrusted
26973  * $sce.getTrusted(context, value)} rather than to the value directly.  Directives use {@link
26974  * ng.$sce#parseAs $sce.parseAs} rather than `$parse` to watch attribute bindings, which performs the
26975  * {@link ng.$sce#getTrusted $sce.getTrusted} behind the scenes on non-constant literals.
26976  *
26977  * As an example, {@link ng.directive:ngBindHtml ngBindHtml} uses {@link
26978  * ng.$sce#parseAsHtml $sce.parseAsHtml(binding expression)}.  Here's the actual code (slightly
26979  * simplified):
26980  *
26981  * ```
26982  * var ngBindHtmlDirective = ['$sce', function($sce) {
26983  *   return function(scope, element, attr) {
26984  *     scope.$watch($sce.parseAsHtml(attr.ngBindHtml), function(value) {
26985  *       element.html(value || '');
26986  *     });
26987  *   };
26988  * }];
26989  * ```
26990  *
26991  * ## Impact on loading templates
26992  *
26993  * This applies both to the {@link ng.directive:ngInclude `ng-include`} directive as well as
26994  * `templateUrl`'s specified by {@link guide/directive directives}.
26995  *
26996  * By default, Angular only loads templates from the same domain and protocol as the application
26997  * document.  This is done by calling {@link ng.$sce#getTrustedResourceUrl
26998  * $sce.getTrustedResourceUrl} on the template URL.  To load templates from other domains and/or
26999  * protocols, you may either {@link ng.$sceDelegateProvider#resourceUrlWhitelist whitelist
27000  * them} or {@link ng.$sce#trustAsResourceUrl wrap it} into a trusted value.
27001  *
27002  * *Please note*:
27003  * The browser's
27004  * [Same Origin Policy](https://code.google.com/p/browsersec/wiki/Part2#Same-origin_policy_for_XMLHttpRequest)
27005  * and [Cross-Origin Resource Sharing (CORS)](http://www.w3.org/TR/cors/)
27006  * policy apply in addition to this and may further restrict whether the template is successfully
27007  * loaded.  This means that without the right CORS policy, loading templates from a different domain
27008  * won't work on all browsers.  Also, loading templates from `file://` URL does not work on some
27009  * browsers.
27010  *
27011  * ## This feels like too much overhead
27012  *
27013  * It's important to remember that SCE only applies to interpolation expressions.
27014  *
27015  * If your expressions are constant literals, they're automatically trusted and you don't need to
27016  * call `$sce.trustAs` on them (remember to include the `ngSanitize` module) (e.g.
27017  * `<div ng-bind-html="'<b>implicitly trusted</b>'"></div>`) just works.
27018  *
27019  * Additionally, `a[href]` and `img[src]` automatically sanitize their URLs and do not pass them
27020  * through {@link ng.$sce#getTrusted $sce.getTrusted}.  SCE doesn't play a role here.
27021  *
27022  * The included {@link ng.$sceDelegate $sceDelegate} comes with sane defaults to allow you to load
27023  * templates in `ng-include` from your application's domain without having to even know about SCE.
27024  * It blocks loading templates from other domains or loading templates over http from an https
27025  * served document.  You can change these by setting your own custom {@link
27026  * ng.$sceDelegateProvider#resourceUrlWhitelist whitelists} and {@link
27027  * ng.$sceDelegateProvider#resourceUrlBlacklist blacklists} for matching such URLs.
27028  *
27029  * This significantly reduces the overhead.  It is far easier to pay the small overhead and have an
27030  * application that's secure and can be audited to verify that with much more ease than bolting
27031  * security onto an application later.
27032  *
27033  * <a name="contexts"></a>
27034  * ## What trusted context types are supported?
27035  *
27036  * | Context             | Notes          |
27037  * |---------------------|----------------|
27038  * | `$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. |
27039  * | `$sce.CSS`          | For CSS that's safe to source into the application.  Currently unused.  Feel free to use it in your own directives. |
27040  * | `$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. |
27041  * | `$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. |
27042  * | `$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. |
27043  *
27044  * ## Format of items in {@link ng.$sceDelegateProvider#resourceUrlWhitelist resourceUrlWhitelist}/{@link ng.$sceDelegateProvider#resourceUrlBlacklist Blacklist} <a name="resourceUrlPatternItem"></a>
27045  *
27046  *  Each element in these arrays must be one of the following:
27047  *
27048  *  - **'self'**
27049  *    - The special **string**, `'self'`, can be used to match against all URLs of the **same
27050  *      domain** as the application document using the **same protocol**.
27051  *  - **String** (except the special value `'self'`)
27052  *    - The string is matched against the full *normalized / absolute URL* of the resource
27053  *      being tested (substring matches are not good enough.)
27054  *    - There are exactly **two wildcard sequences** - `*` and `**`.  All other characters
27055  *      match themselves.
27056  *    - `*`: matches zero or more occurrences of any character other than one of the following 6
27057  *      characters: '`:`', '`/`', '`.`', '`?`', '`&`' and '`;`'.  It's a useful wildcard for use
27058  *      in a whitelist.
27059  *    - `**`: matches zero or more occurrences of *any* character.  As such, it's not
27060  *      appropriate for use in a scheme, domain, etc. as it would match too much.  (e.g.
27061  *      http://**.example.com/ would match http://evil.com/?ignore=.example.com/ and that might
27062  *      not have been the intention.)  Its usage at the very end of the path is ok.  (e.g.
27063  *      http://foo.example.com/templates/**).
27064  *  - **RegExp** (*see caveat below*)
27065  *    - *Caveat*:  While regular expressions are powerful and offer great flexibility,  their syntax
27066  *      (and all the inevitable escaping) makes them *harder to maintain*.  It's easy to
27067  *      accidentally introduce a bug when one updates a complex expression (imho, all regexes should
27068  *      have good test coverage).  For instance, the use of `.` in the regex is correct only in a
27069  *      small number of cases.  A `.` character in the regex used when matching the scheme or a
27070  *      subdomain could be matched against a `:` or literal `.` that was likely not intended.   It
27071  *      is highly recommended to use the string patterns and only fall back to regular expressions
27072  *      as a last resort.
27073  *    - The regular expression must be an instance of RegExp (i.e. not a string.)  It is
27074  *      matched against the **entire** *normalized / absolute URL* of the resource being tested
27075  *      (even when the RegExp did not have the `^` and `$` codes.)  In addition, any flags
27076  *      present on the RegExp (such as multiline, global, ignoreCase) are ignored.
27077  *    - If you are generating your JavaScript from some other templating engine (not
27078  *      recommended, e.g. in issue [#4006](https://github.com/angular/angular.js/issues/4006)),
27079  *      remember to escape your regular expression (and be aware that you might need more than
27080  *      one level of escaping depending on your templating engine and the way you interpolated
27081  *      the value.)  Do make use of your platform's escaping mechanism as it might be good
27082  *      enough before coding your own.  E.g. Ruby has
27083  *      [Regexp.escape(str)](http://www.ruby-doc.org/core-2.0.0/Regexp.html#method-c-escape)
27084  *      and Python has [re.escape](http://docs.python.org/library/re.html#re.escape).
27085  *      Javascript lacks a similar built in function for escaping.  Take a look at Google
27086  *      Closure library's [goog.string.regExpEscape(s)](
27087  *      http://docs.closure-library.googlecode.com/git/closure_goog_string_string.js.source.html#line962).
27088  *
27089  * Refer {@link ng.$sceDelegateProvider $sceDelegateProvider} for an example.
27090  *
27091  * ## Show me an example using SCE.
27092  *
27093  * <example module="mySceApp" deps="angular-sanitize.js">
27094  * <file name="index.html">
27095  *   <div ng-controller="AppController as myCtrl">
27096  *     <i ng-bind-html="myCtrl.explicitlyTrustedHtml" id="explicitlyTrustedHtml"></i><br><br>
27097  *     <b>User comments</b><br>
27098  *     By default, HTML that isn't explicitly trusted (e.g. Alice's comment) is sanitized when
27099  *     $sanitize is available.  If $sanitize isn't available, this results in an error instead of an
27100  *     exploit.
27101  *     <div class="well">
27102  *       <div ng-repeat="userComment in myCtrl.userComments">
27103  *         <b>{{userComment.name}}</b>:
27104  *         <span ng-bind-html="userComment.htmlComment" class="htmlComment"></span>
27105  *         <br>
27106  *       </div>
27107  *     </div>
27108  *   </div>
27109  * </file>
27110  *
27111  * <file name="script.js">
27112  *   angular.module('mySceApp', ['ngSanitize'])
27113  *     .controller('AppController', ['$http', '$templateCache', '$sce',
27114  *       function($http, $templateCache, $sce) {
27115  *         var self = this;
27116  *         $http.get("test_data.json", {cache: $templateCache}).success(function(userComments) {
27117  *           self.userComments = userComments;
27118  *         });
27119  *         self.explicitlyTrustedHtml = $sce.trustAsHtml(
27120  *             '<span onmouseover="this.textContent=&quot;Explicitly trusted HTML bypasses ' +
27121  *             'sanitization.&quot;">Hover over this text.</span>');
27122  *       }]);
27123  * </file>
27124  *
27125  * <file name="test_data.json">
27126  * [
27127  *   { "name": "Alice",
27128  *     "htmlComment":
27129  *         "<span onmouseover='this.textContent=\"PWN3D!\"'>Is <i>anyone</i> reading this?</span>"
27130  *   },
27131  *   { "name": "Bob",
27132  *     "htmlComment": "<i>Yes!</i>  Am I the only other one?"
27133  *   }
27134  * ]
27135  * </file>
27136  *
27137  * <file name="protractor.js" type="protractor">
27138  *   describe('SCE doc demo', function() {
27139  *     it('should sanitize untrusted values', function() {
27140  *       expect(element.all(by.css('.htmlComment')).first().getInnerHtml())
27141  *           .toBe('<span>Is <i>anyone</i> reading this?</span>');
27142  *     });
27143  *
27144  *     it('should NOT sanitize explicitly trusted values', function() {
27145  *       expect(element(by.id('explicitlyTrustedHtml')).getInnerHtml()).toBe(
27146  *           '<span onmouseover="this.textContent=&quot;Explicitly trusted HTML bypasses ' +
27147  *           'sanitization.&quot;">Hover over this text.</span>');
27148  *     });
27149  *   });
27150  * </file>
27151  * </example>
27152  *
27153  *
27154  *
27155  * ## Can I disable SCE completely?
27156  *
27157  * Yes, you can.  However, this is strongly discouraged.  SCE gives you a lot of security benefits
27158  * for little coding overhead.  It will be much harder to take an SCE disabled application and
27159  * either secure it on your own or enable SCE at a later stage.  It might make sense to disable SCE
27160  * for cases where you have a lot of existing code that was written before SCE was introduced and
27161  * you're migrating them a module at a time.
27162  *
27163  * That said, here's how you can completely disable SCE:
27164  *
27165  * ```
27166  * angular.module('myAppWithSceDisabledmyApp', []).config(function($sceProvider) {
27167  *   // Completely disable SCE.  For demonstration purposes only!
27168  *   // Do not use in new projects.
27169  *   $sceProvider.enabled(false);
27170  * });
27171  * ```
27172  *
27173  */
27174 /* jshint maxlen: 100 */
27175
27176 function $SceProvider() {
27177   var enabled = true;
27178
27179   /**
27180    * @ngdoc method
27181    * @name $sceProvider#enabled
27182    * @kind function
27183    *
27184    * @param {boolean=} value If provided, then enables/disables SCE.
27185    * @return {boolean} true if SCE is enabled, false otherwise.
27186    *
27187    * @description
27188    * Enables/disables SCE and returns the current value.
27189    */
27190   this.enabled = function(value) {
27191     if (arguments.length) {
27192       enabled = !!value;
27193     }
27194     return enabled;
27195   };
27196
27197
27198   /* Design notes on the default implementation for SCE.
27199    *
27200    * The API contract for the SCE delegate
27201    * -------------------------------------
27202    * The SCE delegate object must provide the following 3 methods:
27203    *
27204    * - trustAs(contextEnum, value)
27205    *     This method is used to tell the SCE service that the provided value is OK to use in the
27206    *     contexts specified by contextEnum.  It must return an object that will be accepted by
27207    *     getTrusted() for a compatible contextEnum and return this value.
27208    *
27209    * - valueOf(value)
27210    *     For values that were not produced by trustAs(), return them as is.  For values that were
27211    *     produced by trustAs(), return the corresponding input value to trustAs.  Basically, if
27212    *     trustAs is wrapping the given values into some type, this operation unwraps it when given
27213    *     such a value.
27214    *
27215    * - getTrusted(contextEnum, value)
27216    *     This function should return the a value that is safe to use in the context specified by
27217    *     contextEnum or throw and exception otherwise.
27218    *
27219    * NOTE: This contract deliberately does NOT state that values returned by trustAs() must be
27220    * opaque or wrapped in some holder object.  That happens to be an implementation detail.  For
27221    * instance, an implementation could maintain a registry of all trusted objects by context.  In
27222    * such a case, trustAs() would return the same object that was passed in.  getTrusted() would
27223    * return the same object passed in if it was found in the registry under a compatible context or
27224    * throw an exception otherwise.  An implementation might only wrap values some of the time based
27225    * on some criteria.  getTrusted() might return a value and not throw an exception for special
27226    * constants or objects even if not wrapped.  All such implementations fulfill this contract.
27227    *
27228    *
27229    * A note on the inheritance model for SCE contexts
27230    * ------------------------------------------------
27231    * I've used inheritance and made RESOURCE_URL wrapped types a subtype of URL wrapped types.  This
27232    * is purely an implementation details.
27233    *
27234    * The contract is simply this:
27235    *
27236    *     getTrusted($sce.RESOURCE_URL, value) succeeding implies that getTrusted($sce.URL, value)
27237    *     will also succeed.
27238    *
27239    * Inheritance happens to capture this in a natural way.  In some future, we
27240    * may not use inheritance anymore.  That is OK because no code outside of
27241    * sce.js and sceSpecs.js would need to be aware of this detail.
27242    */
27243
27244   this.$get = ['$parse', '$sceDelegate', function(
27245                 $parse,   $sceDelegate) {
27246     // Prereq: Ensure that we're not running in IE<11 quirks mode.  In that mode, IE < 11 allow
27247     // the "expression(javascript expression)" syntax which is insecure.
27248     if (enabled && msie < 8) {
27249       throw $sceMinErr('iequirks',
27250         'Strict Contextual Escaping does not support Internet Explorer version < 11 in quirks ' +
27251         'mode.  You can fix this by adding the text <!doctype html> to the top of your HTML ' +
27252         'document.  See http://docs.angularjs.org/api/ng.$sce for more information.');
27253     }
27254
27255     var sce = shallowCopy(SCE_CONTEXTS);
27256
27257     /**
27258      * @ngdoc method
27259      * @name $sce#isEnabled
27260      * @kind function
27261      *
27262      * @return {Boolean} true if SCE is enabled, false otherwise.  If you want to set the value, you
27263      * have to do it at module config time on {@link ng.$sceProvider $sceProvider}.
27264      *
27265      * @description
27266      * Returns a boolean indicating if SCE is enabled.
27267      */
27268     sce.isEnabled = function() {
27269       return enabled;
27270     };
27271     sce.trustAs = $sceDelegate.trustAs;
27272     sce.getTrusted = $sceDelegate.getTrusted;
27273     sce.valueOf = $sceDelegate.valueOf;
27274
27275     if (!enabled) {
27276       sce.trustAs = sce.getTrusted = function(type, value) { return value; };
27277       sce.valueOf = identity;
27278     }
27279
27280     /**
27281      * @ngdoc method
27282      * @name $sce#parseAs
27283      *
27284      * @description
27285      * Converts Angular {@link guide/expression expression} into a function.  This is like {@link
27286      * ng.$parse $parse} and is identical when the expression is a literal constant.  Otherwise, it
27287      * wraps the expression in a call to {@link ng.$sce#getTrusted $sce.getTrusted(*type*,
27288      * *result*)}
27289      *
27290      * @param {string} type The kind of SCE context in which this result will be used.
27291      * @param {string} expression String expression to compile.
27292      * @returns {function(context, locals)} a function which represents the compiled expression:
27293      *
27294      *    * `context` – `{object}` – an object against which any expressions embedded in the strings
27295      *      are evaluated against (typically a scope object).
27296      *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
27297      *      `context`.
27298      */
27299     sce.parseAs = function sceParseAs(type, expr) {
27300       var parsed = $parse(expr);
27301       if (parsed.literal && parsed.constant) {
27302         return parsed;
27303       } else {
27304         return $parse(expr, function(value) {
27305           return sce.getTrusted(type, value);
27306         });
27307       }
27308     };
27309
27310     /**
27311      * @ngdoc method
27312      * @name $sce#trustAs
27313      *
27314      * @description
27315      * Delegates to {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs`}.  As such,
27316      * returns an object that is trusted by angular for use in specified strict contextual
27317      * escaping contexts (such as ng-bind-html, ng-include, any src attribute
27318      * interpolation, any dom event binding attribute interpolation such as for onclick,  etc.)
27319      * that uses the provided value.  See * {@link ng.$sce $sce} for enabling strict contextual
27320      * escaping.
27321      *
27322      * @param {string} type The kind of context in which this value is safe for use.  e.g. url,
27323      *   resourceUrl, html, js and css.
27324      * @param {*} value The value that that should be considered trusted/safe.
27325      * @returns {*} A value that can be used to stand in for the provided `value` in places
27326      * where Angular expects a $sce.trustAs() return value.
27327      */
27328
27329     /**
27330      * @ngdoc method
27331      * @name $sce#trustAsHtml
27332      *
27333      * @description
27334      * Shorthand method.  `$sce.trustAsHtml(value)` →
27335      *     {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.HTML, value)`}
27336      *
27337      * @param {*} value The value to trustAs.
27338      * @returns {*} An object that can be passed to {@link ng.$sce#getTrustedHtml
27339      *     $sce.getTrustedHtml(value)} to obtain the original value.  (privileged directives
27340      *     only accept expressions that are either literal constants or are the
27341      *     return value of {@link ng.$sce#trustAs $sce.trustAs}.)
27342      */
27343
27344     /**
27345      * @ngdoc method
27346      * @name $sce#trustAsUrl
27347      *
27348      * @description
27349      * Shorthand method.  `$sce.trustAsUrl(value)` →
27350      *     {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.URL, value)`}
27351      *
27352      * @param {*} value The value to trustAs.
27353      * @returns {*} An object that can be passed to {@link ng.$sce#getTrustedUrl
27354      *     $sce.getTrustedUrl(value)} to obtain the original value.  (privileged directives
27355      *     only accept expressions that are either literal constants or are the
27356      *     return value of {@link ng.$sce#trustAs $sce.trustAs}.)
27357      */
27358
27359     /**
27360      * @ngdoc method
27361      * @name $sce#trustAsResourceUrl
27362      *
27363      * @description
27364      * Shorthand method.  `$sce.trustAsResourceUrl(value)` →
27365      *     {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.RESOURCE_URL, value)`}
27366      *
27367      * @param {*} value The value to trustAs.
27368      * @returns {*} An object that can be passed to {@link ng.$sce#getTrustedResourceUrl
27369      *     $sce.getTrustedResourceUrl(value)} to obtain the original value.  (privileged directives
27370      *     only accept expressions that are either literal constants or are the return
27371      *     value of {@link ng.$sce#trustAs $sce.trustAs}.)
27372      */
27373
27374     /**
27375      * @ngdoc method
27376      * @name $sce#trustAsJs
27377      *
27378      * @description
27379      * Shorthand method.  `$sce.trustAsJs(value)` →
27380      *     {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.JS, value)`}
27381      *
27382      * @param {*} value The value to trustAs.
27383      * @returns {*} An object that can be passed to {@link ng.$sce#getTrustedJs
27384      *     $sce.getTrustedJs(value)} to obtain the original value.  (privileged directives
27385      *     only accept expressions that are either literal constants or are the
27386      *     return value of {@link ng.$sce#trustAs $sce.trustAs}.)
27387      */
27388
27389     /**
27390      * @ngdoc method
27391      * @name $sce#getTrusted
27392      *
27393      * @description
27394      * Delegates to {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted`}.  As such,
27395      * takes the result of a {@link ng.$sce#trustAs `$sce.trustAs`}() call and returns the
27396      * originally supplied value if the queried context type is a supertype of the created type.
27397      * If this condition isn't satisfied, throws an exception.
27398      *
27399      * @param {string} type The kind of context in which this value is to be used.
27400      * @param {*} maybeTrusted The result of a prior {@link ng.$sce#trustAs `$sce.trustAs`}
27401      *                         call.
27402      * @returns {*} The value the was originally provided to
27403      *              {@link ng.$sce#trustAs `$sce.trustAs`} if valid in this context.
27404      *              Otherwise, throws an exception.
27405      */
27406
27407     /**
27408      * @ngdoc method
27409      * @name $sce#getTrustedHtml
27410      *
27411      * @description
27412      * Shorthand method.  `$sce.getTrustedHtml(value)` →
27413      *     {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.HTML, value)`}
27414      *
27415      * @param {*} value The value to pass to `$sce.getTrusted`.
27416      * @returns {*} The return value of `$sce.getTrusted($sce.HTML, value)`
27417      */
27418
27419     /**
27420      * @ngdoc method
27421      * @name $sce#getTrustedCss
27422      *
27423      * @description
27424      * Shorthand method.  `$sce.getTrustedCss(value)` →
27425      *     {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.CSS, value)`}
27426      *
27427      * @param {*} value The value to pass to `$sce.getTrusted`.
27428      * @returns {*} The return value of `$sce.getTrusted($sce.CSS, value)`
27429      */
27430
27431     /**
27432      * @ngdoc method
27433      * @name $sce#getTrustedUrl
27434      *
27435      * @description
27436      * Shorthand method.  `$sce.getTrustedUrl(value)` →
27437      *     {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.URL, value)`}
27438      *
27439      * @param {*} value The value to pass to `$sce.getTrusted`.
27440      * @returns {*} The return value of `$sce.getTrusted($sce.URL, value)`
27441      */
27442
27443     /**
27444      * @ngdoc method
27445      * @name $sce#getTrustedResourceUrl
27446      *
27447      * @description
27448      * Shorthand method.  `$sce.getTrustedResourceUrl(value)` →
27449      *     {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.RESOURCE_URL, value)`}
27450      *
27451      * @param {*} value The value to pass to `$sceDelegate.getTrusted`.
27452      * @returns {*} The return value of `$sce.getTrusted($sce.RESOURCE_URL, value)`
27453      */
27454
27455     /**
27456      * @ngdoc method
27457      * @name $sce#getTrustedJs
27458      *
27459      * @description
27460      * Shorthand method.  `$sce.getTrustedJs(value)` →
27461      *     {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.JS, value)`}
27462      *
27463      * @param {*} value The value to pass to `$sce.getTrusted`.
27464      * @returns {*} The return value of `$sce.getTrusted($sce.JS, value)`
27465      */
27466
27467     /**
27468      * @ngdoc method
27469      * @name $sce#parseAsHtml
27470      *
27471      * @description
27472      * Shorthand method.  `$sce.parseAsHtml(expression string)` →
27473      *     {@link ng.$sce#parseAs `$sce.parseAs($sce.HTML, value)`}
27474      *
27475      * @param {string} expression String expression to compile.
27476      * @returns {function(context, locals)} a function which represents the compiled expression:
27477      *
27478      *    * `context` – `{object}` – an object against which any expressions embedded in the strings
27479      *      are evaluated against (typically a scope object).
27480      *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
27481      *      `context`.
27482      */
27483
27484     /**
27485      * @ngdoc method
27486      * @name $sce#parseAsCss
27487      *
27488      * @description
27489      * Shorthand method.  `$sce.parseAsCss(value)` →
27490      *     {@link ng.$sce#parseAs `$sce.parseAs($sce.CSS, value)`}
27491      *
27492      * @param {string} expression String expression to compile.
27493      * @returns {function(context, locals)} a function which represents the compiled expression:
27494      *
27495      *    * `context` – `{object}` – an object against which any expressions embedded in the strings
27496      *      are evaluated against (typically a scope object).
27497      *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
27498      *      `context`.
27499      */
27500
27501     /**
27502      * @ngdoc method
27503      * @name $sce#parseAsUrl
27504      *
27505      * @description
27506      * Shorthand method.  `$sce.parseAsUrl(value)` →
27507      *     {@link ng.$sce#parseAs `$sce.parseAs($sce.URL, value)`}
27508      *
27509      * @param {string} expression String expression to compile.
27510      * @returns {function(context, locals)} a function which represents the compiled expression:
27511      *
27512      *    * `context` – `{object}` – an object against which any expressions embedded in the strings
27513      *      are evaluated against (typically a scope object).
27514      *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
27515      *      `context`.
27516      */
27517
27518     /**
27519      * @ngdoc method
27520      * @name $sce#parseAsResourceUrl
27521      *
27522      * @description
27523      * Shorthand method.  `$sce.parseAsResourceUrl(value)` →
27524      *     {@link ng.$sce#parseAs `$sce.parseAs($sce.RESOURCE_URL, value)`}
27525      *
27526      * @param {string} expression String expression to compile.
27527      * @returns {function(context, locals)} a function which represents the compiled expression:
27528      *
27529      *    * `context` – `{object}` – an object against which any expressions embedded in the strings
27530      *      are evaluated against (typically a scope object).
27531      *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
27532      *      `context`.
27533      */
27534
27535     /**
27536      * @ngdoc method
27537      * @name $sce#parseAsJs
27538      *
27539      * @description
27540      * Shorthand method.  `$sce.parseAsJs(value)` →
27541      *     {@link ng.$sce#parseAs `$sce.parseAs($sce.JS, value)`}
27542      *
27543      * @param {string} expression String expression to compile.
27544      * @returns {function(context, locals)} a function which represents the compiled expression:
27545      *
27546      *    * `context` – `{object}` – an object against which any expressions embedded in the strings
27547      *      are evaluated against (typically a scope object).
27548      *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
27549      *      `context`.
27550      */
27551
27552     // Shorthand delegations.
27553     var parse = sce.parseAs,
27554         getTrusted = sce.getTrusted,
27555         trustAs = sce.trustAs;
27556
27557     forEach(SCE_CONTEXTS, function(enumValue, name) {
27558       var lName = lowercase(name);
27559       sce[camelCase("parse_as_" + lName)] = function(expr) {
27560         return parse(enumValue, expr);
27561       };
27562       sce[camelCase("get_trusted_" + lName)] = function(value) {
27563         return getTrusted(enumValue, value);
27564       };
27565       sce[camelCase("trust_as_" + lName)] = function(value) {
27566         return trustAs(enumValue, value);
27567       };
27568     });
27569
27570     return sce;
27571   }];
27572 }
27573
27574 /**
27575  * !!! This is an undocumented "private" service !!!
27576  *
27577  * @name $sniffer
27578  * @requires $window
27579  * @requires $document
27580  *
27581  * @property {boolean} history Does the browser support html5 history api ?
27582  * @property {boolean} transitions Does the browser support CSS transition events ?
27583  * @property {boolean} animations Does the browser support CSS animation events ?
27584  *
27585  * @description
27586  * This is very simple implementation of testing browser's features.
27587  */
27588 function $SnifferProvider() {
27589   this.$get = ['$window', '$document', function($window, $document) {
27590     var eventSupport = {},
27591         android =
27592           toInt((/android (\d+)/.exec(lowercase(($window.navigator || {}).userAgent)) || [])[1]),
27593         boxee = /Boxee/i.test(($window.navigator || {}).userAgent),
27594         document = $document[0] || {},
27595         vendorPrefix,
27596         vendorRegex = /^(Moz|webkit|ms)(?=[A-Z])/,
27597         bodyStyle = document.body && document.body.style,
27598         transitions = false,
27599         animations = false,
27600         match;
27601
27602     if (bodyStyle) {
27603       for (var prop in bodyStyle) {
27604         if (match = vendorRegex.exec(prop)) {
27605           vendorPrefix = match[0];
27606           vendorPrefix = vendorPrefix.substr(0, 1).toUpperCase() + vendorPrefix.substr(1);
27607           break;
27608         }
27609       }
27610
27611       if (!vendorPrefix) {
27612         vendorPrefix = ('WebkitOpacity' in bodyStyle) && 'webkit';
27613       }
27614
27615       transitions = !!(('transition' in bodyStyle) || (vendorPrefix + 'Transition' in bodyStyle));
27616       animations  = !!(('animation' in bodyStyle) || (vendorPrefix + 'Animation' in bodyStyle));
27617
27618       if (android && (!transitions ||  !animations)) {
27619         transitions = isString(bodyStyle.webkitTransition);
27620         animations = isString(bodyStyle.webkitAnimation);
27621       }
27622     }
27623
27624
27625     return {
27626       // Android has history.pushState, but it does not update location correctly
27627       // so let's not use the history API at all.
27628       // http://code.google.com/p/android/issues/detail?id=17471
27629       // https://github.com/angular/angular.js/issues/904
27630
27631       // older webkit browser (533.9) on Boxee box has exactly the same problem as Android has
27632       // so let's not use the history API also
27633       // We are purposefully using `!(android < 4)` to cover the case when `android` is undefined
27634       // jshint -W018
27635       history: !!($window.history && $window.history.pushState && !(android < 4) && !boxee),
27636       // jshint +W018
27637       hasEvent: function(event) {
27638         // IE9 implements 'input' event it's so fubared that we rather pretend that it doesn't have
27639         // it. In particular the event is not fired when backspace or delete key are pressed or
27640         // when cut operation is performed.
27641         // IE10+ implements 'input' event but it erroneously fires under various situations,
27642         // e.g. when placeholder changes, or a form is focused.
27643         if (event === 'input' && msie <= 11) return false;
27644
27645         if (isUndefined(eventSupport[event])) {
27646           var divElm = document.createElement('div');
27647           eventSupport[event] = 'on' + event in divElm;
27648         }
27649
27650         return eventSupport[event];
27651       },
27652       csp: csp(),
27653       vendorPrefix: vendorPrefix,
27654       transitions: transitions,
27655       animations: animations,
27656       android: android
27657     };
27658   }];
27659 }
27660
27661 var $compileMinErr = minErr('$compile');
27662
27663 /**
27664  * @ngdoc provider
27665  * @name $templateRequestProvider
27666  * @description
27667  * Used to configure the options passed to the {@link $http} service when making a template request.
27668  *
27669  * For example, it can be used for specifying the "Accept" header that is sent to the server, when
27670  * requesting a template.
27671  */
27672 function $TemplateRequestProvider() {
27673
27674   var httpOptions;
27675
27676   /**
27677    * @ngdoc method
27678    * @name $templateRequestProvider#httpOptions
27679    * @description
27680    * The options to be passed to the {@link $http} service when making the request.
27681    * You can use this to override options such as the "Accept" header for template requests.
27682    *
27683    * The {@link $templateRequest} will set the `cache` and the `transformResponse` properties of the
27684    * options if not overridden here.
27685    *
27686    * @param {string=} value new value for the {@link $http} options.
27687    * @returns {string|self} Returns the {@link $http} options when used as getter and self if used as setter.
27688    */
27689   this.httpOptions = function(val) {
27690     if (val) {
27691       httpOptions = val;
27692       return this;
27693     }
27694     return httpOptions;
27695   };
27696
27697   /**
27698    * @ngdoc service
27699    * @name $templateRequest
27700    *
27701    * @description
27702    * The `$templateRequest` service runs security checks then downloads the provided template using
27703    * `$http` and, upon success, stores the contents inside of `$templateCache`. If the HTTP request
27704    * fails or the response data of the HTTP request is empty, a `$compile` error will be thrown (the
27705    * exception can be thwarted by setting the 2nd parameter of the function to true). Note that the
27706    * contents of `$templateCache` are trusted, so the call to `$sce.getTrustedUrl(tpl)` is omitted
27707    * when `tpl` is of type string and `$templateCache` has the matching entry.
27708    *
27709    * If you want to pass custom options to the `$http` service, such as setting the Accept header you
27710    * can configure this via {@link $templateRequestProvider#httpOptions}.
27711    *
27712    * @param {string|TrustedResourceUrl} tpl The HTTP request template URL
27713    * @param {boolean=} ignoreRequestError Whether or not to ignore the exception when the request fails or the template is empty
27714    *
27715    * @return {Promise} a promise for the HTTP response data of the given URL.
27716    *
27717    * @property {number} totalPendingRequests total amount of pending template requests being downloaded.
27718    */
27719   this.$get = ['$templateCache', '$http', '$q', '$sce', function($templateCache, $http, $q, $sce) {
27720
27721     function handleRequestFn(tpl, ignoreRequestError) {
27722       handleRequestFn.totalPendingRequests++;
27723
27724       // We consider the template cache holds only trusted templates, so
27725       // there's no need to go through whitelisting again for keys that already
27726       // are included in there. This also makes Angular accept any script
27727       // directive, no matter its name. However, we still need to unwrap trusted
27728       // types.
27729       if (!isString(tpl) || !$templateCache.get(tpl)) {
27730         tpl = $sce.getTrustedResourceUrl(tpl);
27731       }
27732
27733       var transformResponse = $http.defaults && $http.defaults.transformResponse;
27734
27735       if (isArray(transformResponse)) {
27736         transformResponse = transformResponse.filter(function(transformer) {
27737           return transformer !== defaultHttpResponseTransform;
27738         });
27739       } else if (transformResponse === defaultHttpResponseTransform) {
27740         transformResponse = null;
27741       }
27742
27743       return $http.get(tpl, extend({
27744           cache: $templateCache,
27745           transformResponse: transformResponse
27746         }, httpOptions))
27747         ['finally'](function() {
27748           handleRequestFn.totalPendingRequests--;
27749         })
27750         .then(function(response) {
27751           $templateCache.put(tpl, response.data);
27752           return response.data;
27753         }, handleError);
27754
27755       function handleError(resp) {
27756         if (!ignoreRequestError) {
27757           throw $compileMinErr('tpload', 'Failed to load template: {0} (HTTP status: {1} {2})',
27758             tpl, resp.status, resp.statusText);
27759         }
27760         return $q.reject(resp);
27761       }
27762     }
27763
27764     handleRequestFn.totalPendingRequests = 0;
27765
27766     return handleRequestFn;
27767   }];
27768 }
27769
27770 function $$TestabilityProvider() {
27771   this.$get = ['$rootScope', '$browser', '$location',
27772        function($rootScope,   $browser,   $location) {
27773
27774     /**
27775      * @name $testability
27776      *
27777      * @description
27778      * The private $$testability service provides a collection of methods for use when debugging
27779      * or by automated test and debugging tools.
27780      */
27781     var testability = {};
27782
27783     /**
27784      * @name $$testability#findBindings
27785      *
27786      * @description
27787      * Returns an array of elements that are bound (via ng-bind or {{}})
27788      * to expressions matching the input.
27789      *
27790      * @param {Element} element The element root to search from.
27791      * @param {string} expression The binding expression to match.
27792      * @param {boolean} opt_exactMatch If true, only returns exact matches
27793      *     for the expression. Filters and whitespace are ignored.
27794      */
27795     testability.findBindings = function(element, expression, opt_exactMatch) {
27796       var bindings = element.getElementsByClassName('ng-binding');
27797       var matches = [];
27798       forEach(bindings, function(binding) {
27799         var dataBinding = angular.element(binding).data('$binding');
27800         if (dataBinding) {
27801           forEach(dataBinding, function(bindingName) {
27802             if (opt_exactMatch) {
27803               var matcher = new RegExp('(^|\\s)' + escapeForRegexp(expression) + '(\\s|\\||$)');
27804               if (matcher.test(bindingName)) {
27805                 matches.push(binding);
27806               }
27807             } else {
27808               if (bindingName.indexOf(expression) != -1) {
27809                 matches.push(binding);
27810               }
27811             }
27812           });
27813         }
27814       });
27815       return matches;
27816     };
27817
27818     /**
27819      * @name $$testability#findModels
27820      *
27821      * @description
27822      * Returns an array of elements that are two-way found via ng-model to
27823      * expressions matching the input.
27824      *
27825      * @param {Element} element The element root to search from.
27826      * @param {string} expression The model expression to match.
27827      * @param {boolean} opt_exactMatch If true, only returns exact matches
27828      *     for the expression.
27829      */
27830     testability.findModels = function(element, expression, opt_exactMatch) {
27831       var prefixes = ['ng-', 'data-ng-', 'ng\\:'];
27832       for (var p = 0; p < prefixes.length; ++p) {
27833         var attributeEquals = opt_exactMatch ? '=' : '*=';
27834         var selector = '[' + prefixes[p] + 'model' + attributeEquals + '"' + expression + '"]';
27835         var elements = element.querySelectorAll(selector);
27836         if (elements.length) {
27837           return elements;
27838         }
27839       }
27840     };
27841
27842     /**
27843      * @name $$testability#getLocation
27844      *
27845      * @description
27846      * Shortcut for getting the location in a browser agnostic way. Returns
27847      *     the path, search, and hash. (e.g. /path?a=b#hash)
27848      */
27849     testability.getLocation = function() {
27850       return $location.url();
27851     };
27852
27853     /**
27854      * @name $$testability#setLocation
27855      *
27856      * @description
27857      * Shortcut for navigating to a location without doing a full page reload.
27858      *
27859      * @param {string} url The location url (path, search and hash,
27860      *     e.g. /path?a=b#hash) to go to.
27861      */
27862     testability.setLocation = function(url) {
27863       if (url !== $location.url()) {
27864         $location.url(url);
27865         $rootScope.$digest();
27866       }
27867     };
27868
27869     /**
27870      * @name $$testability#whenStable
27871      *
27872      * @description
27873      * Calls the callback when $timeout and $http requests are completed.
27874      *
27875      * @param {function} callback
27876      */
27877     testability.whenStable = function(callback) {
27878       $browser.notifyWhenNoOutstandingRequests(callback);
27879     };
27880
27881     return testability;
27882   }];
27883 }
27884
27885 function $TimeoutProvider() {
27886   this.$get = ['$rootScope', '$browser', '$q', '$$q', '$exceptionHandler',
27887        function($rootScope,   $browser,   $q,   $$q,   $exceptionHandler) {
27888
27889     var deferreds = {};
27890
27891
27892      /**
27893       * @ngdoc service
27894       * @name $timeout
27895       *
27896       * @description
27897       * Angular's wrapper for `window.setTimeout`. The `fn` function is wrapped into a try/catch
27898       * block and delegates any exceptions to
27899       * {@link ng.$exceptionHandler $exceptionHandler} service.
27900       *
27901       * The return value of calling `$timeout` is a promise, which will be resolved when
27902       * the delay has passed and the timeout function, if provided, is executed.
27903       *
27904       * To cancel a timeout request, call `$timeout.cancel(promise)`.
27905       *
27906       * In tests you can use {@link ngMock.$timeout `$timeout.flush()`} to
27907       * synchronously flush the queue of deferred functions.
27908       *
27909       * If you only want a promise that will be resolved after some specified delay
27910       * then you can call `$timeout` without the `fn` function.
27911       *
27912       * @param {function()=} fn A function, whose execution should be delayed.
27913       * @param {number=} [delay=0] Delay in milliseconds.
27914       * @param {boolean=} [invokeApply=true] If set to `false` skips model dirty checking, otherwise
27915       *   will invoke `fn` within the {@link ng.$rootScope.Scope#$apply $apply} block.
27916       * @param {...*=} Pass additional parameters to the executed function.
27917       * @returns {Promise} Promise that will be resolved when the timeout is reached. The promise
27918       *   will be resolved with the return value of the `fn` function.
27919       *
27920       */
27921     function timeout(fn, delay, invokeApply) {
27922       if (!isFunction(fn)) {
27923         invokeApply = delay;
27924         delay = fn;
27925         fn = noop;
27926       }
27927
27928       var args = sliceArgs(arguments, 3),
27929           skipApply = (isDefined(invokeApply) && !invokeApply),
27930           deferred = (skipApply ? $$q : $q).defer(),
27931           promise = deferred.promise,
27932           timeoutId;
27933
27934       timeoutId = $browser.defer(function() {
27935         try {
27936           deferred.resolve(fn.apply(null, args));
27937         } catch (e) {
27938           deferred.reject(e);
27939           $exceptionHandler(e);
27940         }
27941         finally {
27942           delete deferreds[promise.$$timeoutId];
27943         }
27944
27945         if (!skipApply) $rootScope.$apply();
27946       }, delay);
27947
27948       promise.$$timeoutId = timeoutId;
27949       deferreds[timeoutId] = deferred;
27950
27951       return promise;
27952     }
27953
27954
27955      /**
27956       * @ngdoc method
27957       * @name $timeout#cancel
27958       *
27959       * @description
27960       * Cancels a task associated with the `promise`. As a result of this, the promise will be
27961       * resolved with a rejection.
27962       *
27963       * @param {Promise=} promise Promise returned by the `$timeout` function.
27964       * @returns {boolean} Returns `true` if the task hasn't executed yet and was successfully
27965       *   canceled.
27966       */
27967     timeout.cancel = function(promise) {
27968       if (promise && promise.$$timeoutId in deferreds) {
27969         deferreds[promise.$$timeoutId].reject('canceled');
27970         delete deferreds[promise.$$timeoutId];
27971         return $browser.defer.cancel(promise.$$timeoutId);
27972       }
27973       return false;
27974     };
27975
27976     return timeout;
27977   }];
27978 }
27979
27980 // NOTE:  The usage of window and document instead of $window and $document here is
27981 // deliberate.  This service depends on the specific behavior of anchor nodes created by the
27982 // browser (resolving and parsing URLs) that is unlikely to be provided by mock objects and
27983 // cause us to break tests.  In addition, when the browser resolves a URL for XHR, it
27984 // doesn't know about mocked locations and resolves URLs to the real document - which is
27985 // exactly the behavior needed here.  There is little value is mocking these out for this
27986 // service.
27987 var urlParsingNode = document.createElement("a");
27988 var originUrl = urlResolve(window.location.href);
27989
27990
27991 /**
27992  *
27993  * Implementation Notes for non-IE browsers
27994  * ----------------------------------------
27995  * Assigning a URL to the href property of an anchor DOM node, even one attached to the DOM,
27996  * results both in the normalizing and parsing of the URL.  Normalizing means that a relative
27997  * URL will be resolved into an absolute URL in the context of the application document.
27998  * Parsing means that the anchor node's host, hostname, protocol, port, pathname and related
27999  * properties are all populated to reflect the normalized URL.  This approach has wide
28000  * compatibility - Safari 1+, Mozilla 1+, Opera 7+,e etc.  See
28001  * http://www.aptana.com/reference/html/api/HTMLAnchorElement.html
28002  *
28003  * Implementation Notes for IE
28004  * ---------------------------
28005  * IE <= 10 normalizes the URL when assigned to the anchor node similar to the other
28006  * browsers.  However, the parsed components will not be set if the URL assigned did not specify
28007  * them.  (e.g. if you assign a.href = "foo", then a.protocol, a.host, etc. will be empty.)  We
28008  * work around that by performing the parsing in a 2nd step by taking a previously normalized
28009  * URL (e.g. by assigning to a.href) and assigning it a.href again.  This correctly populates the
28010  * properties such as protocol, hostname, port, etc.
28011  *
28012  * References:
28013  *   http://developer.mozilla.org/en-US/docs/Web/API/HTMLAnchorElement
28014  *   http://www.aptana.com/reference/html/api/HTMLAnchorElement.html
28015  *   http://url.spec.whatwg.org/#urlutils
28016  *   https://github.com/angular/angular.js/pull/2902
28017  *   http://james.padolsey.com/javascript/parsing-urls-with-the-dom/
28018  *
28019  * @kind function
28020  * @param {string} url The URL to be parsed.
28021  * @description Normalizes and parses a URL.
28022  * @returns {object} Returns the normalized URL as a dictionary.
28023  *
28024  *   | member name   | Description    |
28025  *   |---------------|----------------|
28026  *   | href          | A normalized version of the provided URL if it was not an absolute URL |
28027  *   | protocol      | The protocol including the trailing colon                              |
28028  *   | host          | The host and port (if the port is non-default) of the normalizedUrl    |
28029  *   | search        | The search params, minus the question mark                             |
28030  *   | hash          | The hash string, minus the hash symbol
28031  *   | hostname      | The hostname
28032  *   | port          | The port, without ":"
28033  *   | pathname      | The pathname, beginning with "/"
28034  *
28035  */
28036 function urlResolve(url) {
28037   var href = url;
28038
28039   if (msie) {
28040     // Normalize before parse.  Refer Implementation Notes on why this is
28041     // done in two steps on IE.
28042     urlParsingNode.setAttribute("href", href);
28043     href = urlParsingNode.href;
28044   }
28045
28046   urlParsingNode.setAttribute('href', href);
28047
28048   // urlParsingNode provides the UrlUtils interface - http://url.spec.whatwg.org/#urlutils
28049   return {
28050     href: urlParsingNode.href,
28051     protocol: urlParsingNode.protocol ? urlParsingNode.protocol.replace(/:$/, '') : '',
28052     host: urlParsingNode.host,
28053     search: urlParsingNode.search ? urlParsingNode.search.replace(/^\?/, '') : '',
28054     hash: urlParsingNode.hash ? urlParsingNode.hash.replace(/^#/, '') : '',
28055     hostname: urlParsingNode.hostname,
28056     port: urlParsingNode.port,
28057     pathname: (urlParsingNode.pathname.charAt(0) === '/')
28058       ? urlParsingNode.pathname
28059       : '/' + urlParsingNode.pathname
28060   };
28061 }
28062
28063 /**
28064  * Parse a request URL and determine whether this is a same-origin request as the application document.
28065  *
28066  * @param {string|object} requestUrl The url of the request as a string that will be resolved
28067  * or a parsed URL object.
28068  * @returns {boolean} Whether the request is for the same origin as the application document.
28069  */
28070 function urlIsSameOrigin(requestUrl) {
28071   var parsed = (isString(requestUrl)) ? urlResolve(requestUrl) : requestUrl;
28072   return (parsed.protocol === originUrl.protocol &&
28073           parsed.host === originUrl.host);
28074 }
28075
28076 /**
28077  * @ngdoc service
28078  * @name $window
28079  *
28080  * @description
28081  * A reference to the browser's `window` object. While `window`
28082  * is globally available in JavaScript, it causes testability problems, because
28083  * it is a global variable. In angular we always refer to it through the
28084  * `$window` service, so it may be overridden, removed or mocked for testing.
28085  *
28086  * Expressions, like the one defined for the `ngClick` directive in the example
28087  * below, are evaluated with respect to the current scope.  Therefore, there is
28088  * no risk of inadvertently coding in a dependency on a global value in such an
28089  * expression.
28090  *
28091  * @example
28092    <example module="windowExample">
28093      <file name="index.html">
28094        <script>
28095          angular.module('windowExample', [])
28096            .controller('ExampleController', ['$scope', '$window', function($scope, $window) {
28097              $scope.greeting = 'Hello, World!';
28098              $scope.doGreeting = function(greeting) {
28099                $window.alert(greeting);
28100              };
28101            }]);
28102        </script>
28103        <div ng-controller="ExampleController">
28104          <input type="text" ng-model="greeting" aria-label="greeting" />
28105          <button ng-click="doGreeting(greeting)">ALERT</button>
28106        </div>
28107      </file>
28108      <file name="protractor.js" type="protractor">
28109       it('should display the greeting in the input box', function() {
28110        element(by.model('greeting')).sendKeys('Hello, E2E Tests');
28111        // If we click the button it will block the test runner
28112        // element(':button').click();
28113       });
28114      </file>
28115    </example>
28116  */
28117 function $WindowProvider() {
28118   this.$get = valueFn(window);
28119 }
28120
28121 /**
28122  * @name $$cookieReader
28123  * @requires $document
28124  *
28125  * @description
28126  * This is a private service for reading cookies used by $http and ngCookies
28127  *
28128  * @return {Object} a key/value map of the current cookies
28129  */
28130 function $$CookieReader($document) {
28131   var rawDocument = $document[0] || {};
28132   var lastCookies = {};
28133   var lastCookieString = '';
28134
28135   function safeDecodeURIComponent(str) {
28136     try {
28137       return decodeURIComponent(str);
28138     } catch (e) {
28139       return str;
28140     }
28141   }
28142
28143   return function() {
28144     var cookieArray, cookie, i, index, name;
28145     var currentCookieString = rawDocument.cookie || '';
28146
28147     if (currentCookieString !== lastCookieString) {
28148       lastCookieString = currentCookieString;
28149       cookieArray = lastCookieString.split('; ');
28150       lastCookies = {};
28151
28152       for (i = 0; i < cookieArray.length; i++) {
28153         cookie = cookieArray[i];
28154         index = cookie.indexOf('=');
28155         if (index > 0) { //ignore nameless cookies
28156           name = safeDecodeURIComponent(cookie.substring(0, index));
28157           // the first value that is seen for a cookie is the most
28158           // specific one.  values for the same cookie name that
28159           // follow are for less specific paths.
28160           if (isUndefined(lastCookies[name])) {
28161             lastCookies[name] = safeDecodeURIComponent(cookie.substring(index + 1));
28162           }
28163         }
28164       }
28165     }
28166     return lastCookies;
28167   };
28168 }
28169
28170 $$CookieReader.$inject = ['$document'];
28171
28172 function $$CookieReaderProvider() {
28173   this.$get = $$CookieReader;
28174 }
28175
28176 /* global currencyFilter: true,
28177  dateFilter: true,
28178  filterFilter: true,
28179  jsonFilter: true,
28180  limitToFilter: true,
28181  lowercaseFilter: true,
28182  numberFilter: true,
28183  orderByFilter: true,
28184  uppercaseFilter: true,
28185  */
28186
28187 /**
28188  * @ngdoc provider
28189  * @name $filterProvider
28190  * @description
28191  *
28192  * Filters are just functions which transform input to an output. However filters need to be
28193  * Dependency Injected. To achieve this a filter definition consists of a factory function which is
28194  * annotated with dependencies and is responsible for creating a filter function.
28195  *
28196  * <div class="alert alert-warning">
28197  * **Note:** Filter names must be valid angular {@link expression} identifiers, such as `uppercase` or `orderBy`.
28198  * Names with special characters, such as hyphens and dots, are not allowed. If you wish to namespace
28199  * your filters, then you can use capitalization (`myappSubsectionFilterx`) or underscores
28200  * (`myapp_subsection_filterx`).
28201  * </div>
28202  *
28203  * ```js
28204  *   // Filter registration
28205  *   function MyModule($provide, $filterProvider) {
28206  *     // create a service to demonstrate injection (not always needed)
28207  *     $provide.value('greet', function(name){
28208  *       return 'Hello ' + name + '!';
28209  *     });
28210  *
28211  *     // register a filter factory which uses the
28212  *     // greet service to demonstrate DI.
28213  *     $filterProvider.register('greet', function(greet){
28214  *       // return the filter function which uses the greet service
28215  *       // to generate salutation
28216  *       return function(text) {
28217  *         // filters need to be forgiving so check input validity
28218  *         return text && greet(text) || text;
28219  *       };
28220  *     });
28221  *   }
28222  * ```
28223  *
28224  * The filter function is registered with the `$injector` under the filter name suffix with
28225  * `Filter`.
28226  *
28227  * ```js
28228  *   it('should be the same instance', inject(
28229  *     function($filterProvider) {
28230  *       $filterProvider.register('reverse', function(){
28231  *         return ...;
28232  *       });
28233  *     },
28234  *     function($filter, reverseFilter) {
28235  *       expect($filter('reverse')).toBe(reverseFilter);
28236  *     });
28237  * ```
28238  *
28239  *
28240  * For more information about how angular filters work, and how to create your own filters, see
28241  * {@link guide/filter Filters} in the Angular Developer Guide.
28242  */
28243
28244 /**
28245  * @ngdoc service
28246  * @name $filter
28247  * @kind function
28248  * @description
28249  * Filters are used for formatting data displayed to the user.
28250  *
28251  * The general syntax in templates is as follows:
28252  *
28253  *         {{ expression [| filter_name[:parameter_value] ... ] }}
28254  *
28255  * @param {String} name Name of the filter function to retrieve
28256  * @return {Function} the filter function
28257  * @example
28258    <example name="$filter" module="filterExample">
28259      <file name="index.html">
28260        <div ng-controller="MainCtrl">
28261         <h3>{{ originalText }}</h3>
28262         <h3>{{ filteredText }}</h3>
28263        </div>
28264      </file>
28265
28266      <file name="script.js">
28267       angular.module('filterExample', [])
28268       .controller('MainCtrl', function($scope, $filter) {
28269         $scope.originalText = 'hello';
28270         $scope.filteredText = $filter('uppercase')($scope.originalText);
28271       });
28272      </file>
28273    </example>
28274   */
28275 $FilterProvider.$inject = ['$provide'];
28276 function $FilterProvider($provide) {
28277   var suffix = 'Filter';
28278
28279   /**
28280    * @ngdoc method
28281    * @name $filterProvider#register
28282    * @param {string|Object} name Name of the filter function, or an object map of filters where
28283    *    the keys are the filter names and the values are the filter factories.
28284    *
28285    *    <div class="alert alert-warning">
28286    *    **Note:** Filter names must be valid angular {@link expression} identifiers, such as `uppercase` or `orderBy`.
28287    *    Names with special characters, such as hyphens and dots, are not allowed. If you wish to namespace
28288    *    your filters, then you can use capitalization (`myappSubsectionFilterx`) or underscores
28289    *    (`myapp_subsection_filterx`).
28290    *    </div>
28291     * @param {Function} factory If the first argument was a string, a factory function for the filter to be registered.
28292    * @returns {Object} Registered filter instance, or if a map of filters was provided then a map
28293    *    of the registered filter instances.
28294    */
28295   function register(name, factory) {
28296     if (isObject(name)) {
28297       var filters = {};
28298       forEach(name, function(filter, key) {
28299         filters[key] = register(key, filter);
28300       });
28301       return filters;
28302     } else {
28303       return $provide.factory(name + suffix, factory);
28304     }
28305   }
28306   this.register = register;
28307
28308   this.$get = ['$injector', function($injector) {
28309     return function(name) {
28310       return $injector.get(name + suffix);
28311     };
28312   }];
28313
28314   ////////////////////////////////////////
28315
28316   /* global
28317     currencyFilter: false,
28318     dateFilter: false,
28319     filterFilter: false,
28320     jsonFilter: false,
28321     limitToFilter: false,
28322     lowercaseFilter: false,
28323     numberFilter: false,
28324     orderByFilter: false,
28325     uppercaseFilter: false,
28326   */
28327
28328   register('currency', currencyFilter);
28329   register('date', dateFilter);
28330   register('filter', filterFilter);
28331   register('json', jsonFilter);
28332   register('limitTo', limitToFilter);
28333   register('lowercase', lowercaseFilter);
28334   register('number', numberFilter);
28335   register('orderBy', orderByFilter);
28336   register('uppercase', uppercaseFilter);
28337 }
28338
28339 /**
28340  * @ngdoc filter
28341  * @name filter
28342  * @kind function
28343  *
28344  * @description
28345  * Selects a subset of items from `array` and returns it as a new array.
28346  *
28347  * @param {Array} array The source array.
28348  * @param {string|Object|function()} expression The predicate to be used for selecting items from
28349  *   `array`.
28350  *
28351  *   Can be one of:
28352  *
28353  *   - `string`: The string is used for matching against the contents of the `array`. All strings or
28354  *     objects with string properties in `array` that match this string will be returned. This also
28355  *     applies to nested object properties.
28356  *     The predicate can be negated by prefixing the string with `!`.
28357  *
28358  *   - `Object`: A pattern object can be used to filter specific properties on objects contained
28359  *     by `array`. For example `{name:"M", phone:"1"}` predicate will return an array of items
28360  *     which have property `name` containing "M" and property `phone` containing "1". A special
28361  *     property name `$` can be used (as in `{$:"text"}`) to accept a match against any
28362  *     property of the object or its nested object properties. That's equivalent to the simple
28363  *     substring match with a `string` as described above. The predicate can be negated by prefixing
28364  *     the string with `!`.
28365  *     For example `{name: "!M"}` predicate will return an array of items which have property `name`
28366  *     not containing "M".
28367  *
28368  *     Note that a named property will match properties on the same level only, while the special
28369  *     `$` property will match properties on the same level or deeper. E.g. an array item like
28370  *     `{name: {first: 'John', last: 'Doe'}}` will **not** be matched by `{name: 'John'}`, but
28371  *     **will** be matched by `{$: 'John'}`.
28372  *
28373  *   - `function(value, index, array)`: A predicate function can be used to write arbitrary filters.
28374  *     The function is called for each element of the array, with the element, its index, and
28375  *     the entire array itself as arguments.
28376  *
28377  *     The final result is an array of those elements that the predicate returned true for.
28378  *
28379  * @param {function(actual, expected)|true|undefined} comparator Comparator which is used in
28380  *     determining if the expected value (from the filter expression) and actual value (from
28381  *     the object in the array) should be considered a match.
28382  *
28383  *   Can be one of:
28384  *
28385  *   - `function(actual, expected)`:
28386  *     The function will be given the object value and the predicate value to compare and
28387  *     should return true if both values should be considered equal.
28388  *
28389  *   - `true`: A shorthand for `function(actual, expected) { return angular.equals(actual, expected)}`.
28390  *     This is essentially strict comparison of expected and actual.
28391  *
28392  *   - `false|undefined`: A short hand for a function which will look for a substring match in case
28393  *     insensitive way.
28394  *
28395  *     Primitive values are converted to strings. Objects are not compared against primitives,
28396  *     unless they have a custom `toString` method (e.g. `Date` objects).
28397  *
28398  * @example
28399    <example>
28400      <file name="index.html">
28401        <div ng-init="friends = [{name:'John', phone:'555-1276'},
28402                                 {name:'Mary', phone:'800-BIG-MARY'},
28403                                 {name:'Mike', phone:'555-4321'},
28404                                 {name:'Adam', phone:'555-5678'},
28405                                 {name:'Julie', phone:'555-8765'},
28406                                 {name:'Juliette', phone:'555-5678'}]"></div>
28407
28408        <label>Search: <input ng-model="searchText"></label>
28409        <table id="searchTextResults">
28410          <tr><th>Name</th><th>Phone</th></tr>
28411          <tr ng-repeat="friend in friends | filter:searchText">
28412            <td>{{friend.name}}</td>
28413            <td>{{friend.phone}}</td>
28414          </tr>
28415        </table>
28416        <hr>
28417        <label>Any: <input ng-model="search.$"></label> <br>
28418        <label>Name only <input ng-model="search.name"></label><br>
28419        <label>Phone only <input ng-model="search.phone"></label><br>
28420        <label>Equality <input type="checkbox" ng-model="strict"></label><br>
28421        <table id="searchObjResults">
28422          <tr><th>Name</th><th>Phone</th></tr>
28423          <tr ng-repeat="friendObj in friends | filter:search:strict">
28424            <td>{{friendObj.name}}</td>
28425            <td>{{friendObj.phone}}</td>
28426          </tr>
28427        </table>
28428      </file>
28429      <file name="protractor.js" type="protractor">
28430        var expectFriendNames = function(expectedNames, key) {
28431          element.all(by.repeater(key + ' in friends').column(key + '.name')).then(function(arr) {
28432            arr.forEach(function(wd, i) {
28433              expect(wd.getText()).toMatch(expectedNames[i]);
28434            });
28435          });
28436        };
28437
28438        it('should search across all fields when filtering with a string', function() {
28439          var searchText = element(by.model('searchText'));
28440          searchText.clear();
28441          searchText.sendKeys('m');
28442          expectFriendNames(['Mary', 'Mike', 'Adam'], 'friend');
28443
28444          searchText.clear();
28445          searchText.sendKeys('76');
28446          expectFriendNames(['John', 'Julie'], 'friend');
28447        });
28448
28449        it('should search in specific fields when filtering with a predicate object', function() {
28450          var searchAny = element(by.model('search.$'));
28451          searchAny.clear();
28452          searchAny.sendKeys('i');
28453          expectFriendNames(['Mary', 'Mike', 'Julie', 'Juliette'], 'friendObj');
28454        });
28455        it('should use a equal comparison when comparator is true', function() {
28456          var searchName = element(by.model('search.name'));
28457          var strict = element(by.model('strict'));
28458          searchName.clear();
28459          searchName.sendKeys('Julie');
28460          strict.click();
28461          expectFriendNames(['Julie'], 'friendObj');
28462        });
28463      </file>
28464    </example>
28465  */
28466 function filterFilter() {
28467   return function(array, expression, comparator) {
28468     if (!isArrayLike(array)) {
28469       if (array == null) {
28470         return array;
28471       } else {
28472         throw minErr('filter')('notarray', 'Expected array but received: {0}', array);
28473       }
28474     }
28475
28476     var expressionType = getTypeForFilter(expression);
28477     var predicateFn;
28478     var matchAgainstAnyProp;
28479
28480     switch (expressionType) {
28481       case 'function':
28482         predicateFn = expression;
28483         break;
28484       case 'boolean':
28485       case 'null':
28486       case 'number':
28487       case 'string':
28488         matchAgainstAnyProp = true;
28489         //jshint -W086
28490       case 'object':
28491         //jshint +W086
28492         predicateFn = createPredicateFn(expression, comparator, matchAgainstAnyProp);
28493         break;
28494       default:
28495         return array;
28496     }
28497
28498     return Array.prototype.filter.call(array, predicateFn);
28499   };
28500 }
28501
28502 // Helper functions for `filterFilter`
28503 function createPredicateFn(expression, comparator, matchAgainstAnyProp) {
28504   var shouldMatchPrimitives = isObject(expression) && ('$' in expression);
28505   var predicateFn;
28506
28507   if (comparator === true) {
28508     comparator = equals;
28509   } else if (!isFunction(comparator)) {
28510     comparator = function(actual, expected) {
28511       if (isUndefined(actual)) {
28512         // No substring matching against `undefined`
28513         return false;
28514       }
28515       if ((actual === null) || (expected === null)) {
28516         // No substring matching against `null`; only match against `null`
28517         return actual === expected;
28518       }
28519       if (isObject(expected) || (isObject(actual) && !hasCustomToString(actual))) {
28520         // Should not compare primitives against objects, unless they have custom `toString` method
28521         return false;
28522       }
28523
28524       actual = lowercase('' + actual);
28525       expected = lowercase('' + expected);
28526       return actual.indexOf(expected) !== -1;
28527     };
28528   }
28529
28530   predicateFn = function(item) {
28531     if (shouldMatchPrimitives && !isObject(item)) {
28532       return deepCompare(item, expression.$, comparator, false);
28533     }
28534     return deepCompare(item, expression, comparator, matchAgainstAnyProp);
28535   };
28536
28537   return predicateFn;
28538 }
28539
28540 function deepCompare(actual, expected, comparator, matchAgainstAnyProp, dontMatchWholeObject) {
28541   var actualType = getTypeForFilter(actual);
28542   var expectedType = getTypeForFilter(expected);
28543
28544   if ((expectedType === 'string') && (expected.charAt(0) === '!')) {
28545     return !deepCompare(actual, expected.substring(1), comparator, matchAgainstAnyProp);
28546   } else if (isArray(actual)) {
28547     // In case `actual` is an array, consider it a match
28548     // if ANY of it's items matches `expected`
28549     return actual.some(function(item) {
28550       return deepCompare(item, expected, comparator, matchAgainstAnyProp);
28551     });
28552   }
28553
28554   switch (actualType) {
28555     case 'object':
28556       var key;
28557       if (matchAgainstAnyProp) {
28558         for (key in actual) {
28559           if ((key.charAt(0) !== '$') && deepCompare(actual[key], expected, comparator, true)) {
28560             return true;
28561           }
28562         }
28563         return dontMatchWholeObject ? false : deepCompare(actual, expected, comparator, false);
28564       } else if (expectedType === 'object') {
28565         for (key in expected) {
28566           var expectedVal = expected[key];
28567           if (isFunction(expectedVal) || isUndefined(expectedVal)) {
28568             continue;
28569           }
28570
28571           var matchAnyProperty = key === '$';
28572           var actualVal = matchAnyProperty ? actual : actual[key];
28573           if (!deepCompare(actualVal, expectedVal, comparator, matchAnyProperty, matchAnyProperty)) {
28574             return false;
28575           }
28576         }
28577         return true;
28578       } else {
28579         return comparator(actual, expected);
28580       }
28581       break;
28582     case 'function':
28583       return false;
28584     default:
28585       return comparator(actual, expected);
28586   }
28587 }
28588
28589 // Used for easily differentiating between `null` and actual `object`
28590 function getTypeForFilter(val) {
28591   return (val === null) ? 'null' : typeof val;
28592 }
28593
28594 var MAX_DIGITS = 22;
28595 var DECIMAL_SEP = '.';
28596 var ZERO_CHAR = '0';
28597
28598 /**
28599  * @ngdoc filter
28600  * @name currency
28601  * @kind function
28602  *
28603  * @description
28604  * Formats a number as a currency (ie $1,234.56). When no currency symbol is provided, default
28605  * symbol for current locale is used.
28606  *
28607  * @param {number} amount Input to filter.
28608  * @param {string=} symbol Currency symbol or identifier to be displayed.
28609  * @param {number=} fractionSize Number of decimal places to round the amount to, defaults to default max fraction size for current locale
28610  * @returns {string} Formatted number.
28611  *
28612  *
28613  * @example
28614    <example module="currencyExample">
28615      <file name="index.html">
28616        <script>
28617          angular.module('currencyExample', [])
28618            .controller('ExampleController', ['$scope', function($scope) {
28619              $scope.amount = 1234.56;
28620            }]);
28621        </script>
28622        <div ng-controller="ExampleController">
28623          <input type="number" ng-model="amount" aria-label="amount"> <br>
28624          default currency symbol ($): <span id="currency-default">{{amount | currency}}</span><br>
28625          custom currency identifier (USD$): <span id="currency-custom">{{amount | currency:"USD$"}}</span>
28626          no fractions (0): <span id="currency-no-fractions">{{amount | currency:"USD$":0}}</span>
28627        </div>
28628      </file>
28629      <file name="protractor.js" type="protractor">
28630        it('should init with 1234.56', function() {
28631          expect(element(by.id('currency-default')).getText()).toBe('$1,234.56');
28632          expect(element(by.id('currency-custom')).getText()).toBe('USD$1,234.56');
28633          expect(element(by.id('currency-no-fractions')).getText()).toBe('USD$1,235');
28634        });
28635        it('should update', function() {
28636          if (browser.params.browser == 'safari') {
28637            // Safari does not understand the minus key. See
28638            // https://github.com/angular/protractor/issues/481
28639            return;
28640          }
28641          element(by.model('amount')).clear();
28642          element(by.model('amount')).sendKeys('-1234');
28643          expect(element(by.id('currency-default')).getText()).toBe('-$1,234.00');
28644          expect(element(by.id('currency-custom')).getText()).toBe('-USD$1,234.00');
28645          expect(element(by.id('currency-no-fractions')).getText()).toBe('-USD$1,234');
28646        });
28647      </file>
28648    </example>
28649  */
28650 currencyFilter.$inject = ['$locale'];
28651 function currencyFilter($locale) {
28652   var formats = $locale.NUMBER_FORMATS;
28653   return function(amount, currencySymbol, fractionSize) {
28654     if (isUndefined(currencySymbol)) {
28655       currencySymbol = formats.CURRENCY_SYM;
28656     }
28657
28658     if (isUndefined(fractionSize)) {
28659       fractionSize = formats.PATTERNS[1].maxFrac;
28660     }
28661
28662     // if null or undefined pass it through
28663     return (amount == null)
28664         ? amount
28665         : formatNumber(amount, formats.PATTERNS[1], formats.GROUP_SEP, formats.DECIMAL_SEP, fractionSize).
28666             replace(/\u00A4/g, currencySymbol);
28667   };
28668 }
28669
28670 /**
28671  * @ngdoc filter
28672  * @name number
28673  * @kind function
28674  *
28675  * @description
28676  * Formats a number as text.
28677  *
28678  * If the input is null or undefined, it will just be returned.
28679  * If the input is infinite (Infinity/-Infinity) the Infinity symbol '∞' is returned.
28680  * If the input is not a number an empty string is returned.
28681  *
28682  *
28683  * @param {number|string} number Number to format.
28684  * @param {(number|string)=} fractionSize Number of decimal places to round the number to.
28685  * If this is not provided then the fraction size is computed from the current locale's number
28686  * formatting pattern. In the case of the default locale, it will be 3.
28687  * @returns {string} Number rounded to fractionSize and places a “,” after each third digit.
28688  *
28689  * @example
28690    <example module="numberFilterExample">
28691      <file name="index.html">
28692        <script>
28693          angular.module('numberFilterExample', [])
28694            .controller('ExampleController', ['$scope', function($scope) {
28695              $scope.val = 1234.56789;
28696            }]);
28697        </script>
28698        <div ng-controller="ExampleController">
28699          <label>Enter number: <input ng-model='val'></label><br>
28700          Default formatting: <span id='number-default'>{{val | number}}</span><br>
28701          No fractions: <span>{{val | number:0}}</span><br>
28702          Negative number: <span>{{-val | number:4}}</span>
28703        </div>
28704      </file>
28705      <file name="protractor.js" type="protractor">
28706        it('should format numbers', function() {
28707          expect(element(by.id('number-default')).getText()).toBe('1,234.568');
28708          expect(element(by.binding('val | number:0')).getText()).toBe('1,235');
28709          expect(element(by.binding('-val | number:4')).getText()).toBe('-1,234.5679');
28710        });
28711
28712        it('should update', function() {
28713          element(by.model('val')).clear();
28714          element(by.model('val')).sendKeys('3374.333');
28715          expect(element(by.id('number-default')).getText()).toBe('3,374.333');
28716          expect(element(by.binding('val | number:0')).getText()).toBe('3,374');
28717          expect(element(by.binding('-val | number:4')).getText()).toBe('-3,374.3330');
28718       });
28719      </file>
28720    </example>
28721  */
28722 numberFilter.$inject = ['$locale'];
28723 function numberFilter($locale) {
28724   var formats = $locale.NUMBER_FORMATS;
28725   return function(number, fractionSize) {
28726
28727     // if null or undefined pass it through
28728     return (number == null)
28729         ? number
28730         : formatNumber(number, formats.PATTERNS[0], formats.GROUP_SEP, formats.DECIMAL_SEP,
28731                        fractionSize);
28732   };
28733 }
28734
28735 /**
28736  * Parse a number (as a string) into three components that can be used
28737  * for formatting the number.
28738  *
28739  * (Significant bits of this parse algorithm came from https://github.com/MikeMcl/big.js/)
28740  *
28741  * @param  {string} numStr The number to parse
28742  * @return {object} An object describing this number, containing the following keys:
28743  *  - d : an array of digits containing leading zeros as necessary
28744  *  - i : the number of the digits in `d` that are to the left of the decimal point
28745  *  - e : the exponent for numbers that would need more than `MAX_DIGITS` digits in `d`
28746  *
28747  */
28748 function parse(numStr) {
28749   var exponent = 0, digits, numberOfIntegerDigits;
28750   var i, j, zeros;
28751
28752   // Decimal point?
28753   if ((numberOfIntegerDigits = numStr.indexOf(DECIMAL_SEP)) > -1) {
28754     numStr = numStr.replace(DECIMAL_SEP, '');
28755   }
28756
28757   // Exponential form?
28758   if ((i = numStr.search(/e/i)) > 0) {
28759     // Work out the exponent.
28760     if (numberOfIntegerDigits < 0) numberOfIntegerDigits = i;
28761     numberOfIntegerDigits += +numStr.slice(i + 1);
28762     numStr = numStr.substring(0, i);
28763   } else if (numberOfIntegerDigits < 0) {
28764     // There was no decimal point or exponent so it is an integer.
28765     numberOfIntegerDigits = numStr.length;
28766   }
28767
28768   // Count the number of leading zeros.
28769   for (i = 0; numStr.charAt(i) == ZERO_CHAR; i++);
28770
28771   if (i == (zeros = numStr.length)) {
28772     // The digits are all zero.
28773     digits = [0];
28774     numberOfIntegerDigits = 1;
28775   } else {
28776     // Count the number of trailing zeros
28777     zeros--;
28778     while (numStr.charAt(zeros) == ZERO_CHAR) zeros--;
28779
28780     // Trailing zeros are insignificant so ignore them
28781     numberOfIntegerDigits -= i;
28782     digits = [];
28783     // Convert string to array of digits without leading/trailing zeros.
28784     for (j = 0; i <= zeros; i++, j++) {
28785       digits[j] = +numStr.charAt(i);
28786     }
28787   }
28788
28789   // If the number overflows the maximum allowed digits then use an exponent.
28790   if (numberOfIntegerDigits > MAX_DIGITS) {
28791     digits = digits.splice(0, MAX_DIGITS - 1);
28792     exponent = numberOfIntegerDigits - 1;
28793     numberOfIntegerDigits = 1;
28794   }
28795
28796   return { d: digits, e: exponent, i: numberOfIntegerDigits };
28797 }
28798
28799 /**
28800  * Round the parsed number to the specified number of decimal places
28801  * This function changed the parsedNumber in-place
28802  */
28803 function roundNumber(parsedNumber, fractionSize, minFrac, maxFrac) {
28804     var digits = parsedNumber.d;
28805     var fractionLen = digits.length - parsedNumber.i;
28806
28807     // determine fractionSize if it is not specified; `+fractionSize` converts it to a number
28808     fractionSize = (isUndefined(fractionSize)) ? Math.min(Math.max(minFrac, fractionLen), maxFrac) : +fractionSize;
28809
28810     // The index of the digit to where rounding is to occur
28811     var roundAt = fractionSize + parsedNumber.i;
28812     var digit = digits[roundAt];
28813
28814     if (roundAt > 0) {
28815       digits.splice(roundAt);
28816     } else {
28817       // We rounded to zero so reset the parsedNumber
28818       parsedNumber.i = 1;
28819       digits.length = roundAt = fractionSize + 1;
28820       for (var i=0; i < roundAt; i++) digits[i] = 0;
28821     }
28822
28823     if (digit >= 5) digits[roundAt - 1]++;
28824
28825     // Pad out with zeros to get the required fraction length
28826     for (; fractionLen < fractionSize; fractionLen++) digits.push(0);
28827
28828
28829     // Do any carrying, e.g. a digit was rounded up to 10
28830     var carry = digits.reduceRight(function(carry, d, i, digits) {
28831       d = d + carry;
28832       digits[i] = d % 10;
28833       return Math.floor(d / 10);
28834     }, 0);
28835     if (carry) {
28836       digits.unshift(carry);
28837       parsedNumber.i++;
28838     }
28839 }
28840
28841 /**
28842  * Format a number into a string
28843  * @param  {number} number       The number to format
28844  * @param  {{
28845  *           minFrac, // the minimum number of digits required in the fraction part of the number
28846  *           maxFrac, // the maximum number of digits required in the fraction part of the number
28847  *           gSize,   // number of digits in each group of separated digits
28848  *           lgSize,  // number of digits in the last group of digits before the decimal separator
28849  *           negPre,  // the string to go in front of a negative number (e.g. `-` or `(`))
28850  *           posPre,  // the string to go in front of a positive number
28851  *           negSuf,  // the string to go after a negative number (e.g. `)`)
28852  *           posSuf   // the string to go after a positive number
28853  *         }} pattern
28854  * @param  {string} groupSep     The string to separate groups of number (e.g. `,`)
28855  * @param  {string} decimalSep   The string to act as the decimal separator (e.g. `.`)
28856  * @param  {[type]} fractionSize The size of the fractional part of the number
28857  * @return {string}              The number formatted as a string
28858  */
28859 function formatNumber(number, pattern, groupSep, decimalSep, fractionSize) {
28860
28861   if (!(isString(number) || isNumber(number)) || isNaN(number)) return '';
28862
28863   var isInfinity = !isFinite(number);
28864   var isZero = false;
28865   var numStr = Math.abs(number) + '',
28866       formattedText = '',
28867       parsedNumber;
28868
28869   if (isInfinity) {
28870     formattedText = '\u221e';
28871   } else {
28872     parsedNumber = parse(numStr);
28873
28874     roundNumber(parsedNumber, fractionSize, pattern.minFrac, pattern.maxFrac);
28875
28876     var digits = parsedNumber.d;
28877     var integerLen = parsedNumber.i;
28878     var exponent = parsedNumber.e;
28879     var decimals = [];
28880     isZero = digits.reduce(function(isZero, d) { return isZero && !d; }, true);
28881
28882     // pad zeros for small numbers
28883     while (integerLen < 0) {
28884       digits.unshift(0);
28885       integerLen++;
28886     }
28887
28888     // extract decimals digits
28889     if (integerLen > 0) {
28890       decimals = digits.splice(integerLen);
28891     } else {
28892       decimals = digits;
28893       digits = [0];
28894     }
28895
28896     // format the integer digits with grouping separators
28897     var groups = [];
28898     if (digits.length > pattern.lgSize) {
28899       groups.unshift(digits.splice(-pattern.lgSize).join(''));
28900     }
28901     while (digits.length > pattern.gSize) {
28902       groups.unshift(digits.splice(-pattern.gSize).join(''));
28903     }
28904     if (digits.length) {
28905       groups.unshift(digits.join(''));
28906     }
28907     formattedText = groups.join(groupSep);
28908
28909     // append the decimal digits
28910     if (decimals.length) {
28911       formattedText += decimalSep + decimals.join('');
28912     }
28913
28914     if (exponent) {
28915       formattedText += 'e+' + exponent;
28916     }
28917   }
28918   if (number < 0 && !isZero) {
28919     return pattern.negPre + formattedText + pattern.negSuf;
28920   } else {
28921     return pattern.posPre + formattedText + pattern.posSuf;
28922   }
28923 }
28924
28925 function padNumber(num, digits, trim) {
28926   var neg = '';
28927   if (num < 0) {
28928     neg =  '-';
28929     num = -num;
28930   }
28931   num = '' + num;
28932   while (num.length < digits) num = ZERO_CHAR + num;
28933   if (trim) {
28934     num = num.substr(num.length - digits);
28935   }
28936   return neg + num;
28937 }
28938
28939
28940 function dateGetter(name, size, offset, trim) {
28941   offset = offset || 0;
28942   return function(date) {
28943     var value = date['get' + name]();
28944     if (offset > 0 || value > -offset) {
28945       value += offset;
28946     }
28947     if (value === 0 && offset == -12) value = 12;
28948     return padNumber(value, size, trim);
28949   };
28950 }
28951
28952 function dateStrGetter(name, shortForm) {
28953   return function(date, formats) {
28954     var value = date['get' + name]();
28955     var get = uppercase(shortForm ? ('SHORT' + name) : name);
28956
28957     return formats[get][value];
28958   };
28959 }
28960
28961 function timeZoneGetter(date, formats, offset) {
28962   var zone = -1 * offset;
28963   var paddedZone = (zone >= 0) ? "+" : "";
28964
28965   paddedZone += padNumber(Math[zone > 0 ? 'floor' : 'ceil'](zone / 60), 2) +
28966                 padNumber(Math.abs(zone % 60), 2);
28967
28968   return paddedZone;
28969 }
28970
28971 function getFirstThursdayOfYear(year) {
28972     // 0 = index of January
28973     var dayOfWeekOnFirst = (new Date(year, 0, 1)).getDay();
28974     // 4 = index of Thursday (+1 to account for 1st = 5)
28975     // 11 = index of *next* Thursday (+1 account for 1st = 12)
28976     return new Date(year, 0, ((dayOfWeekOnFirst <= 4) ? 5 : 12) - dayOfWeekOnFirst);
28977 }
28978
28979 function getThursdayThisWeek(datetime) {
28980     return new Date(datetime.getFullYear(), datetime.getMonth(),
28981       // 4 = index of Thursday
28982       datetime.getDate() + (4 - datetime.getDay()));
28983 }
28984
28985 function weekGetter(size) {
28986    return function(date) {
28987       var firstThurs = getFirstThursdayOfYear(date.getFullYear()),
28988          thisThurs = getThursdayThisWeek(date);
28989
28990       var diff = +thisThurs - +firstThurs,
28991          result = 1 + Math.round(diff / 6.048e8); // 6.048e8 ms per week
28992
28993       return padNumber(result, size);
28994    };
28995 }
28996
28997 function ampmGetter(date, formats) {
28998   return date.getHours() < 12 ? formats.AMPMS[0] : formats.AMPMS[1];
28999 }
29000
29001 function eraGetter(date, formats) {
29002   return date.getFullYear() <= 0 ? formats.ERAS[0] : formats.ERAS[1];
29003 }
29004
29005 function longEraGetter(date, formats) {
29006   return date.getFullYear() <= 0 ? formats.ERANAMES[0] : formats.ERANAMES[1];
29007 }
29008
29009 var DATE_FORMATS = {
29010   yyyy: dateGetter('FullYear', 4),
29011     yy: dateGetter('FullYear', 2, 0, true),
29012      y: dateGetter('FullYear', 1),
29013   MMMM: dateStrGetter('Month'),
29014    MMM: dateStrGetter('Month', true),
29015     MM: dateGetter('Month', 2, 1),
29016      M: dateGetter('Month', 1, 1),
29017     dd: dateGetter('Date', 2),
29018      d: dateGetter('Date', 1),
29019     HH: dateGetter('Hours', 2),
29020      H: dateGetter('Hours', 1),
29021     hh: dateGetter('Hours', 2, -12),
29022      h: dateGetter('Hours', 1, -12),
29023     mm: dateGetter('Minutes', 2),
29024      m: dateGetter('Minutes', 1),
29025     ss: dateGetter('Seconds', 2),
29026      s: dateGetter('Seconds', 1),
29027      // while ISO 8601 requires fractions to be prefixed with `.` or `,`
29028      // we can be just safely rely on using `sss` since we currently don't support single or two digit fractions
29029    sss: dateGetter('Milliseconds', 3),
29030   EEEE: dateStrGetter('Day'),
29031    EEE: dateStrGetter('Day', true),
29032      a: ampmGetter,
29033      Z: timeZoneGetter,
29034     ww: weekGetter(2),
29035      w: weekGetter(1),
29036      G: eraGetter,
29037      GG: eraGetter,
29038      GGG: eraGetter,
29039      GGGG: longEraGetter
29040 };
29041
29042 var DATE_FORMATS_SPLIT = /((?:[^yMdHhmsaZEwG']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|d+|H+|h+|m+|s+|a|Z|G+|w+))(.*)/,
29043     NUMBER_STRING = /^\-?\d+$/;
29044
29045 /**
29046  * @ngdoc filter
29047  * @name date
29048  * @kind function
29049  *
29050  * @description
29051  *   Formats `date` to a string based on the requested `format`.
29052  *
29053  *   `format` string can be composed of the following elements:
29054  *
29055  *   * `'yyyy'`: 4 digit representation of year (e.g. AD 1 => 0001, AD 2010 => 2010)
29056  *   * `'yy'`: 2 digit representation of year, padded (00-99). (e.g. AD 2001 => 01, AD 2010 => 10)
29057  *   * `'y'`: 1 digit representation of year, e.g. (AD 1 => 1, AD 199 => 199)
29058  *   * `'MMMM'`: Month in year (January-December)
29059  *   * `'MMM'`: Month in year (Jan-Dec)
29060  *   * `'MM'`: Month in year, padded (01-12)
29061  *   * `'M'`: Month in year (1-12)
29062  *   * `'dd'`: Day in month, padded (01-31)
29063  *   * `'d'`: Day in month (1-31)
29064  *   * `'EEEE'`: Day in Week,(Sunday-Saturday)
29065  *   * `'EEE'`: Day in Week, (Sun-Sat)
29066  *   * `'HH'`: Hour in day, padded (00-23)
29067  *   * `'H'`: Hour in day (0-23)
29068  *   * `'hh'`: Hour in AM/PM, padded (01-12)
29069  *   * `'h'`: Hour in AM/PM, (1-12)
29070  *   * `'mm'`: Minute in hour, padded (00-59)
29071  *   * `'m'`: Minute in hour (0-59)
29072  *   * `'ss'`: Second in minute, padded (00-59)
29073  *   * `'s'`: Second in minute (0-59)
29074  *   * `'sss'`: Millisecond in second, padded (000-999)
29075  *   * `'a'`: AM/PM marker
29076  *   * `'Z'`: 4 digit (+sign) representation of the timezone offset (-1200-+1200)
29077  *   * `'ww'`: Week of year, padded (00-53). Week 01 is the week with the first Thursday of the year
29078  *   * `'w'`: Week of year (0-53). Week 1 is the week with the first Thursday of the year
29079  *   * `'G'`, `'GG'`, `'GGG'`: The abbreviated form of the era string (e.g. 'AD')
29080  *   * `'GGGG'`: The long form of the era string (e.g. 'Anno Domini')
29081  *
29082  *   `format` string can also be one of the following predefined
29083  *   {@link guide/i18n localizable formats}:
29084  *
29085  *   * `'medium'`: equivalent to `'MMM d, y h:mm:ss a'` for en_US locale
29086  *     (e.g. Sep 3, 2010 12:05:08 PM)
29087  *   * `'short'`: equivalent to `'M/d/yy h:mm a'` for en_US  locale (e.g. 9/3/10 12:05 PM)
29088  *   * `'fullDate'`: equivalent to `'EEEE, MMMM d, y'` for en_US  locale
29089  *     (e.g. Friday, September 3, 2010)
29090  *   * `'longDate'`: equivalent to `'MMMM d, y'` for en_US  locale (e.g. September 3, 2010)
29091  *   * `'mediumDate'`: equivalent to `'MMM d, y'` for en_US  locale (e.g. Sep 3, 2010)
29092  *   * `'shortDate'`: equivalent to `'M/d/yy'` for en_US locale (e.g. 9/3/10)
29093  *   * `'mediumTime'`: equivalent to `'h:mm:ss a'` for en_US locale (e.g. 12:05:08 PM)
29094  *   * `'shortTime'`: equivalent to `'h:mm a'` for en_US locale (e.g. 12:05 PM)
29095  *
29096  *   `format` string can contain literal values. These need to be escaped by surrounding with single quotes (e.g.
29097  *   `"h 'in the morning'"`). In order to output a single quote, escape it - i.e., two single quotes in a sequence
29098  *   (e.g. `"h 'o''clock'"`).
29099  *
29100  * @param {(Date|number|string)} date Date to format either as Date object, milliseconds (string or
29101  *    number) or various ISO 8601 datetime string formats (e.g. yyyy-MM-ddTHH:mm:ss.sssZ and its
29102  *    shorter versions like yyyy-MM-ddTHH:mmZ, yyyy-MM-dd or yyyyMMddTHHmmssZ). If no timezone is
29103  *    specified in the string input, the time is considered to be in the local timezone.
29104  * @param {string=} format Formatting rules (see Description). If not specified,
29105  *    `mediumDate` is used.
29106  * @param {string=} timezone Timezone to be used for formatting. It understands UTC/GMT and the
29107  *    continental US time zone abbreviations, but for general use, use a time zone offset, for
29108  *    example, `'+0430'` (4 hours, 30 minutes east of the Greenwich meridian)
29109  *    If not specified, the timezone of the browser will be used.
29110  * @returns {string} Formatted string or the input if input is not recognized as date/millis.
29111  *
29112  * @example
29113    <example>
29114      <file name="index.html">
29115        <span ng-non-bindable>{{1288323623006 | date:'medium'}}</span>:
29116            <span>{{1288323623006 | date:'medium'}}</span><br>
29117        <span ng-non-bindable>{{1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'}}</span>:
29118           <span>{{1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'}}</span><br>
29119        <span ng-non-bindable>{{1288323623006 | date:'MM/dd/yyyy @ h:mma'}}</span>:
29120           <span>{{'1288323623006' | date:'MM/dd/yyyy @ h:mma'}}</span><br>
29121        <span ng-non-bindable>{{1288323623006 | date:"MM/dd/yyyy 'at' h:mma"}}</span>:
29122           <span>{{'1288323623006' | date:"MM/dd/yyyy 'at' h:mma"}}</span><br>
29123      </file>
29124      <file name="protractor.js" type="protractor">
29125        it('should format date', function() {
29126          expect(element(by.binding("1288323623006 | date:'medium'")).getText()).
29127             toMatch(/Oct 2\d, 2010 \d{1,2}:\d{2}:\d{2} (AM|PM)/);
29128          expect(element(by.binding("1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'")).getText()).
29129             toMatch(/2010\-10\-2\d \d{2}:\d{2}:\d{2} (\-|\+)?\d{4}/);
29130          expect(element(by.binding("'1288323623006' | date:'MM/dd/yyyy @ h:mma'")).getText()).
29131             toMatch(/10\/2\d\/2010 @ \d{1,2}:\d{2}(AM|PM)/);
29132          expect(element(by.binding("'1288323623006' | date:\"MM/dd/yyyy 'at' h:mma\"")).getText()).
29133             toMatch(/10\/2\d\/2010 at \d{1,2}:\d{2}(AM|PM)/);
29134        });
29135      </file>
29136    </example>
29137  */
29138 dateFilter.$inject = ['$locale'];
29139 function dateFilter($locale) {
29140
29141
29142   var R_ISO8601_STR = /^(\d{4})-?(\d\d)-?(\d\d)(?:T(\d\d)(?::?(\d\d)(?::?(\d\d)(?:\.(\d+))?)?)?(Z|([+-])(\d\d):?(\d\d))?)?$/;
29143                      // 1        2       3         4          5          6          7          8  9     10      11
29144   function jsonStringToDate(string) {
29145     var match;
29146     if (match = string.match(R_ISO8601_STR)) {
29147       var date = new Date(0),
29148           tzHour = 0,
29149           tzMin  = 0,
29150           dateSetter = match[8] ? date.setUTCFullYear : date.setFullYear,
29151           timeSetter = match[8] ? date.setUTCHours : date.setHours;
29152
29153       if (match[9]) {
29154         tzHour = toInt(match[9] + match[10]);
29155         tzMin = toInt(match[9] + match[11]);
29156       }
29157       dateSetter.call(date, toInt(match[1]), toInt(match[2]) - 1, toInt(match[3]));
29158       var h = toInt(match[4] || 0) - tzHour;
29159       var m = toInt(match[5] || 0) - tzMin;
29160       var s = toInt(match[6] || 0);
29161       var ms = Math.round(parseFloat('0.' + (match[7] || 0)) * 1000);
29162       timeSetter.call(date, h, m, s, ms);
29163       return date;
29164     }
29165     return string;
29166   }
29167
29168
29169   return function(date, format, timezone) {
29170     var text = '',
29171         parts = [],
29172         fn, match;
29173
29174     format = format || 'mediumDate';
29175     format = $locale.DATETIME_FORMATS[format] || format;
29176     if (isString(date)) {
29177       date = NUMBER_STRING.test(date) ? toInt(date) : jsonStringToDate(date);
29178     }
29179
29180     if (isNumber(date)) {
29181       date = new Date(date);
29182     }
29183
29184     if (!isDate(date) || !isFinite(date.getTime())) {
29185       return date;
29186     }
29187
29188     while (format) {
29189       match = DATE_FORMATS_SPLIT.exec(format);
29190       if (match) {
29191         parts = concat(parts, match, 1);
29192         format = parts.pop();
29193       } else {
29194         parts.push(format);
29195         format = null;
29196       }
29197     }
29198
29199     var dateTimezoneOffset = date.getTimezoneOffset();
29200     if (timezone) {
29201       dateTimezoneOffset = timezoneToOffset(timezone, dateTimezoneOffset);
29202       date = convertTimezoneToLocal(date, timezone, true);
29203     }
29204     forEach(parts, function(value) {
29205       fn = DATE_FORMATS[value];
29206       text += fn ? fn(date, $locale.DATETIME_FORMATS, dateTimezoneOffset)
29207                  : value === "''" ? "'" : value.replace(/(^'|'$)/g, '').replace(/''/g, "'");
29208     });
29209
29210     return text;
29211   };
29212 }
29213
29214
29215 /**
29216  * @ngdoc filter
29217  * @name json
29218  * @kind function
29219  *
29220  * @description
29221  *   Allows you to convert a JavaScript object into JSON string.
29222  *
29223  *   This filter is mostly useful for debugging. When using the double curly {{value}} notation
29224  *   the binding is automatically converted to JSON.
29225  *
29226  * @param {*} object Any JavaScript object (including arrays and primitive types) to filter.
29227  * @param {number=} spacing The number of spaces to use per indentation, defaults to 2.
29228  * @returns {string} JSON string.
29229  *
29230  *
29231  * @example
29232    <example>
29233      <file name="index.html">
29234        <pre id="default-spacing">{{ {'name':'value'} | json }}</pre>
29235        <pre id="custom-spacing">{{ {'name':'value'} | json:4 }}</pre>
29236      </file>
29237      <file name="protractor.js" type="protractor">
29238        it('should jsonify filtered objects', function() {
29239          expect(element(by.id('default-spacing')).getText()).toMatch(/\{\n  "name": ?"value"\n}/);
29240          expect(element(by.id('custom-spacing')).getText()).toMatch(/\{\n    "name": ?"value"\n}/);
29241        });
29242      </file>
29243    </example>
29244  *
29245  */
29246 function jsonFilter() {
29247   return function(object, spacing) {
29248     if (isUndefined(spacing)) {
29249         spacing = 2;
29250     }
29251     return toJson(object, spacing);
29252   };
29253 }
29254
29255
29256 /**
29257  * @ngdoc filter
29258  * @name lowercase
29259  * @kind function
29260  * @description
29261  * Converts string to lowercase.
29262  * @see angular.lowercase
29263  */
29264 var lowercaseFilter = valueFn(lowercase);
29265
29266
29267 /**
29268  * @ngdoc filter
29269  * @name uppercase
29270  * @kind function
29271  * @description
29272  * Converts string to uppercase.
29273  * @see angular.uppercase
29274  */
29275 var uppercaseFilter = valueFn(uppercase);
29276
29277 /**
29278  * @ngdoc filter
29279  * @name limitTo
29280  * @kind function
29281  *
29282  * @description
29283  * Creates a new array or string containing only a specified number of elements. The elements
29284  * are taken from either the beginning or the end of the source array, string or number, as specified by
29285  * the value and sign (positive or negative) of `limit`. If a number is used as input, it is
29286  * converted to a string.
29287  *
29288  * @param {Array|string|number} input Source array, string or number to be limited.
29289  * @param {string|number} limit The length of the returned array or string. If the `limit` number
29290  *     is positive, `limit` number of items from the beginning of the source array/string are copied.
29291  *     If the number is negative, `limit` number  of items from the end of the source array/string
29292  *     are copied. The `limit` will be trimmed if it exceeds `array.length`. If `limit` is undefined,
29293  *     the input will be returned unchanged.
29294  * @param {(string|number)=} begin Index at which to begin limitation. As a negative index, `begin`
29295  *     indicates an offset from the end of `input`. Defaults to `0`.
29296  * @returns {Array|string} A new sub-array or substring of length `limit` or less if input array
29297  *     had less than `limit` elements.
29298  *
29299  * @example
29300    <example module="limitToExample">
29301      <file name="index.html">
29302        <script>
29303          angular.module('limitToExample', [])
29304            .controller('ExampleController', ['$scope', function($scope) {
29305              $scope.numbers = [1,2,3,4,5,6,7,8,9];
29306              $scope.letters = "abcdefghi";
29307              $scope.longNumber = 2345432342;
29308              $scope.numLimit = 3;
29309              $scope.letterLimit = 3;
29310              $scope.longNumberLimit = 3;
29311            }]);
29312        </script>
29313        <div ng-controller="ExampleController">
29314          <label>
29315             Limit {{numbers}} to:
29316             <input type="number" step="1" ng-model="numLimit">
29317          </label>
29318          <p>Output numbers: {{ numbers | limitTo:numLimit }}</p>
29319          <label>
29320             Limit {{letters}} to:
29321             <input type="number" step="1" ng-model="letterLimit">
29322          </label>
29323          <p>Output letters: {{ letters | limitTo:letterLimit }}</p>
29324          <label>
29325             Limit {{longNumber}} to:
29326             <input type="number" step="1" ng-model="longNumberLimit">
29327          </label>
29328          <p>Output long number: {{ longNumber | limitTo:longNumberLimit }}</p>
29329        </div>
29330      </file>
29331      <file name="protractor.js" type="protractor">
29332        var numLimitInput = element(by.model('numLimit'));
29333        var letterLimitInput = element(by.model('letterLimit'));
29334        var longNumberLimitInput = element(by.model('longNumberLimit'));
29335        var limitedNumbers = element(by.binding('numbers | limitTo:numLimit'));
29336        var limitedLetters = element(by.binding('letters | limitTo:letterLimit'));
29337        var limitedLongNumber = element(by.binding('longNumber | limitTo:longNumberLimit'));
29338
29339        it('should limit the number array to first three items', function() {
29340          expect(numLimitInput.getAttribute('value')).toBe('3');
29341          expect(letterLimitInput.getAttribute('value')).toBe('3');
29342          expect(longNumberLimitInput.getAttribute('value')).toBe('3');
29343          expect(limitedNumbers.getText()).toEqual('Output numbers: [1,2,3]');
29344          expect(limitedLetters.getText()).toEqual('Output letters: abc');
29345          expect(limitedLongNumber.getText()).toEqual('Output long number: 234');
29346        });
29347
29348        // There is a bug in safari and protractor that doesn't like the minus key
29349        // it('should update the output when -3 is entered', function() {
29350        //   numLimitInput.clear();
29351        //   numLimitInput.sendKeys('-3');
29352        //   letterLimitInput.clear();
29353        //   letterLimitInput.sendKeys('-3');
29354        //   longNumberLimitInput.clear();
29355        //   longNumberLimitInput.sendKeys('-3');
29356        //   expect(limitedNumbers.getText()).toEqual('Output numbers: [7,8,9]');
29357        //   expect(limitedLetters.getText()).toEqual('Output letters: ghi');
29358        //   expect(limitedLongNumber.getText()).toEqual('Output long number: 342');
29359        // });
29360
29361        it('should not exceed the maximum size of input array', function() {
29362          numLimitInput.clear();
29363          numLimitInput.sendKeys('100');
29364          letterLimitInput.clear();
29365          letterLimitInput.sendKeys('100');
29366          longNumberLimitInput.clear();
29367          longNumberLimitInput.sendKeys('100');
29368          expect(limitedNumbers.getText()).toEqual('Output numbers: [1,2,3,4,5,6,7,8,9]');
29369          expect(limitedLetters.getText()).toEqual('Output letters: abcdefghi');
29370          expect(limitedLongNumber.getText()).toEqual('Output long number: 2345432342');
29371        });
29372      </file>
29373    </example>
29374 */
29375 function limitToFilter() {
29376   return function(input, limit, begin) {
29377     if (Math.abs(Number(limit)) === Infinity) {
29378       limit = Number(limit);
29379     } else {
29380       limit = toInt(limit);
29381     }
29382     if (isNaN(limit)) return input;
29383
29384     if (isNumber(input)) input = input.toString();
29385     if (!isArray(input) && !isString(input)) return input;
29386
29387     begin = (!begin || isNaN(begin)) ? 0 : toInt(begin);
29388     begin = (begin < 0) ? Math.max(0, input.length + begin) : begin;
29389
29390     if (limit >= 0) {
29391       return input.slice(begin, begin + limit);
29392     } else {
29393       if (begin === 0) {
29394         return input.slice(limit, input.length);
29395       } else {
29396         return input.slice(Math.max(0, begin + limit), begin);
29397       }
29398     }
29399   };
29400 }
29401
29402 /**
29403  * @ngdoc filter
29404  * @name orderBy
29405  * @kind function
29406  *
29407  * @description
29408  * Orders a specified `array` by the `expression` predicate. It is ordered alphabetically
29409  * for strings and numerically for numbers. Note: if you notice numbers are not being sorted
29410  * as expected, make sure they are actually being saved as numbers and not strings.
29411  * Array-like values (e.g. NodeLists, jQuery objects, TypedArrays, Strings, etc) are also supported.
29412  *
29413  * @param {Array} array The array (or array-like object) to sort.
29414  * @param {function(*)|string|Array.<(function(*)|string)>=} expression A predicate to be
29415  *    used by the comparator to determine the order of elements.
29416  *
29417  *    Can be one of:
29418  *
29419  *    - `function`: Getter function. The result of this function will be sorted using the
29420  *      `<`, `===`, `>` operator.
29421  *    - `string`: An Angular expression. The result of this expression is used to compare elements
29422  *      (for example `name` to sort by a property called `name` or `name.substr(0, 3)` to sort by
29423  *      3 first characters of a property called `name`). The result of a constant expression
29424  *      is interpreted as a property name to be used in comparisons (for example `"special name"`
29425  *      to sort object by the value of their `special name` property). An expression can be
29426  *      optionally prefixed with `+` or `-` to control ascending or descending sort order
29427  *      (for example, `+name` or `-name`). If no property is provided, (e.g. `'+'`) then the array
29428  *      element itself is used to compare where sorting.
29429  *    - `Array`: An array of function or string predicates. The first predicate in the array
29430  *      is used for sorting, but when two items are equivalent, the next predicate is used.
29431  *
29432  *    If the predicate is missing or empty then it defaults to `'+'`.
29433  *
29434  * @param {boolean=} reverse Reverse the order of the array.
29435  * @returns {Array} Sorted copy of the source array.
29436  *
29437  *
29438  * @example
29439  * The example below demonstrates a simple ngRepeat, where the data is sorted
29440  * by age in descending order (predicate is set to `'-age'`).
29441  * `reverse` is not set, which means it defaults to `false`.
29442    <example module="orderByExample">
29443      <file name="index.html">
29444        <div ng-controller="ExampleController">
29445          <table class="friend">
29446            <tr>
29447              <th>Name</th>
29448              <th>Phone Number</th>
29449              <th>Age</th>
29450            </tr>
29451            <tr ng-repeat="friend in friends | orderBy:'-age'">
29452              <td>{{friend.name}}</td>
29453              <td>{{friend.phone}}</td>
29454              <td>{{friend.age}}</td>
29455            </tr>
29456          </table>
29457        </div>
29458      </file>
29459      <file name="script.js">
29460        angular.module('orderByExample', [])
29461          .controller('ExampleController', ['$scope', function($scope) {
29462            $scope.friends =
29463                [{name:'John', phone:'555-1212', age:10},
29464                 {name:'Mary', phone:'555-9876', age:19},
29465                 {name:'Mike', phone:'555-4321', age:21},
29466                 {name:'Adam', phone:'555-5678', age:35},
29467                 {name:'Julie', phone:'555-8765', age:29}];
29468          }]);
29469      </file>
29470    </example>
29471  *
29472  * The predicate and reverse parameters can be controlled dynamically through scope properties,
29473  * as shown in the next example.
29474  * @example
29475    <example module="orderByExample">
29476      <file name="index.html">
29477        <div ng-controller="ExampleController">
29478          <pre>Sorting predicate = {{predicate}}; reverse = {{reverse}}</pre>
29479          <hr/>
29480          <button ng-click="predicate=''">Set to unsorted</button>
29481          <table class="friend">
29482            <tr>
29483             <th>
29484                 <button ng-click="order('name')">Name</button>
29485                 <span class="sortorder" ng-show="predicate === 'name'" ng-class="{reverse:reverse}"></span>
29486             </th>
29487             <th>
29488                 <button ng-click="order('phone')">Phone Number</button>
29489                 <span class="sortorder" ng-show="predicate === 'phone'" ng-class="{reverse:reverse}"></span>
29490             </th>
29491             <th>
29492                 <button ng-click="order('age')">Age</button>
29493                 <span class="sortorder" ng-show="predicate === 'age'" ng-class="{reverse:reverse}"></span>
29494             </th>
29495            </tr>
29496            <tr ng-repeat="friend in friends | orderBy:predicate:reverse">
29497              <td>{{friend.name}}</td>
29498              <td>{{friend.phone}}</td>
29499              <td>{{friend.age}}</td>
29500            </tr>
29501          </table>
29502        </div>
29503      </file>
29504      <file name="script.js">
29505        angular.module('orderByExample', [])
29506          .controller('ExampleController', ['$scope', function($scope) {
29507            $scope.friends =
29508                [{name:'John', phone:'555-1212', age:10},
29509                 {name:'Mary', phone:'555-9876', age:19},
29510                 {name:'Mike', phone:'555-4321', age:21},
29511                 {name:'Adam', phone:'555-5678', age:35},
29512                 {name:'Julie', phone:'555-8765', age:29}];
29513            $scope.predicate = 'age';
29514            $scope.reverse = true;
29515            $scope.order = function(predicate) {
29516              $scope.reverse = ($scope.predicate === predicate) ? !$scope.reverse : false;
29517              $scope.predicate = predicate;
29518            };
29519          }]);
29520       </file>
29521      <file name="style.css">
29522        .sortorder:after {
29523          content: '\25b2';
29524        }
29525        .sortorder.reverse:after {
29526          content: '\25bc';
29527        }
29528      </file>
29529    </example>
29530  *
29531  * It's also possible to call the orderBy filter manually, by injecting `$filter`, retrieving the
29532  * filter routine with `$filter('orderBy')`, and calling the returned filter routine with the
29533  * desired parameters.
29534  *
29535  * Example:
29536  *
29537  * @example
29538   <example module="orderByExample">
29539     <file name="index.html">
29540     <div ng-controller="ExampleController">
29541       <pre>Sorting predicate = {{predicate}}; reverse = {{reverse}}</pre>
29542       <table class="friend">
29543         <tr>
29544           <th>
29545               <button ng-click="order('name')">Name</button>
29546               <span class="sortorder" ng-show="predicate === 'name'" ng-class="{reverse:reverse}"></span>
29547           </th>
29548           <th>
29549               <button ng-click="order('phone')">Phone Number</button>
29550               <span class="sortorder" ng-show="predicate === 'phone'" ng-class="{reverse:reverse}"></span>
29551           </th>
29552           <th>
29553               <button ng-click="order('age')">Age</button>
29554               <span class="sortorder" ng-show="predicate === 'age'" ng-class="{reverse:reverse}"></span>
29555           </th>
29556         </tr>
29557         <tr ng-repeat="friend in friends">
29558           <td>{{friend.name}}</td>
29559           <td>{{friend.phone}}</td>
29560           <td>{{friend.age}}</td>
29561         </tr>
29562       </table>
29563     </div>
29564     </file>
29565
29566     <file name="script.js">
29567       angular.module('orderByExample', [])
29568         .controller('ExampleController', ['$scope', '$filter', function($scope, $filter) {
29569           var orderBy = $filter('orderBy');
29570           $scope.friends = [
29571             { name: 'John',    phone: '555-1212',    age: 10 },
29572             { name: 'Mary',    phone: '555-9876',    age: 19 },
29573             { name: 'Mike',    phone: '555-4321',    age: 21 },
29574             { name: 'Adam',    phone: '555-5678',    age: 35 },
29575             { name: 'Julie',   phone: '555-8765',    age: 29 }
29576           ];
29577           $scope.order = function(predicate) {
29578             $scope.predicate = predicate;
29579             $scope.reverse = ($scope.predicate === predicate) ? !$scope.reverse : false;
29580             $scope.friends = orderBy($scope.friends, predicate, $scope.reverse);
29581           };
29582           $scope.order('age', true);
29583         }]);
29584     </file>
29585
29586     <file name="style.css">
29587        .sortorder:after {
29588          content: '\25b2';
29589        }
29590        .sortorder.reverse:after {
29591          content: '\25bc';
29592        }
29593     </file>
29594 </example>
29595  */
29596 orderByFilter.$inject = ['$parse'];
29597 function orderByFilter($parse) {
29598   return function(array, sortPredicate, reverseOrder) {
29599
29600     if (array == null) return array;
29601     if (!isArrayLike(array)) {
29602       throw minErr('orderBy')('notarray', 'Expected array but received: {0}', array);
29603     }
29604
29605     if (!isArray(sortPredicate)) { sortPredicate = [sortPredicate]; }
29606     if (sortPredicate.length === 0) { sortPredicate = ['+']; }
29607
29608     var predicates = processPredicates(sortPredicate, reverseOrder);
29609     // Add a predicate at the end that evaluates to the element index. This makes the
29610     // sort stable as it works as a tie-breaker when all the input predicates cannot
29611     // distinguish between two elements.
29612     predicates.push({ get: function() { return {}; }, descending: reverseOrder ? -1 : 1});
29613
29614     // The next three lines are a version of a Swartzian Transform idiom from Perl
29615     // (sometimes called the Decorate-Sort-Undecorate idiom)
29616     // See https://en.wikipedia.org/wiki/Schwartzian_transform
29617     var compareValues = Array.prototype.map.call(array, getComparisonObject);
29618     compareValues.sort(doComparison);
29619     array = compareValues.map(function(item) { return item.value; });
29620
29621     return array;
29622
29623     function getComparisonObject(value, index) {
29624       return {
29625         value: value,
29626         predicateValues: predicates.map(function(predicate) {
29627           return getPredicateValue(predicate.get(value), index);
29628         })
29629       };
29630     }
29631
29632     function doComparison(v1, v2) {
29633       var result = 0;
29634       for (var index=0, length = predicates.length; index < length; ++index) {
29635         result = compare(v1.predicateValues[index], v2.predicateValues[index]) * predicates[index].descending;
29636         if (result) break;
29637       }
29638       return result;
29639     }
29640   };
29641
29642   function processPredicates(sortPredicate, reverseOrder) {
29643     reverseOrder = reverseOrder ? -1 : 1;
29644     return sortPredicate.map(function(predicate) {
29645       var descending = 1, get = identity;
29646
29647       if (isFunction(predicate)) {
29648         get = predicate;
29649       } else if (isString(predicate)) {
29650         if ((predicate.charAt(0) == '+' || predicate.charAt(0) == '-')) {
29651           descending = predicate.charAt(0) == '-' ? -1 : 1;
29652           predicate = predicate.substring(1);
29653         }
29654         if (predicate !== '') {
29655           get = $parse(predicate);
29656           if (get.constant) {
29657             var key = get();
29658             get = function(value) { return value[key]; };
29659           }
29660         }
29661       }
29662       return { get: get, descending: descending * reverseOrder };
29663     });
29664   }
29665
29666   function isPrimitive(value) {
29667     switch (typeof value) {
29668       case 'number': /* falls through */
29669       case 'boolean': /* falls through */
29670       case 'string':
29671         return true;
29672       default:
29673         return false;
29674     }
29675   }
29676
29677   function objectValue(value, index) {
29678     // If `valueOf` is a valid function use that
29679     if (typeof value.valueOf === 'function') {
29680       value = value.valueOf();
29681       if (isPrimitive(value)) return value;
29682     }
29683     // If `toString` is a valid function and not the one from `Object.prototype` use that
29684     if (hasCustomToString(value)) {
29685       value = value.toString();
29686       if (isPrimitive(value)) return value;
29687     }
29688     // We have a basic object so we use the position of the object in the collection
29689     return index;
29690   }
29691
29692   function getPredicateValue(value, index) {
29693     var type = typeof value;
29694     if (value === null) {
29695       type = 'string';
29696       value = 'null';
29697     } else if (type === 'string') {
29698       value = value.toLowerCase();
29699     } else if (type === 'object') {
29700       value = objectValue(value, index);
29701     }
29702     return { value: value, type: type };
29703   }
29704
29705   function compare(v1, v2) {
29706     var result = 0;
29707     if (v1.type === v2.type) {
29708       if (v1.value !== v2.value) {
29709         result = v1.value < v2.value ? -1 : 1;
29710       }
29711     } else {
29712       result = v1.type < v2.type ? -1 : 1;
29713     }
29714     return result;
29715   }
29716 }
29717
29718 function ngDirective(directive) {
29719   if (isFunction(directive)) {
29720     directive = {
29721       link: directive
29722     };
29723   }
29724   directive.restrict = directive.restrict || 'AC';
29725   return valueFn(directive);
29726 }
29727
29728 /**
29729  * @ngdoc directive
29730  * @name a
29731  * @restrict E
29732  *
29733  * @description
29734  * Modifies the default behavior of the html A tag so that the default action is prevented when
29735  * the href attribute is empty.
29736  *
29737  * This change permits the easy creation of action links with the `ngClick` directive
29738  * without changing the location or causing page reloads, e.g.:
29739  * `<a href="" ng-click="list.addItem()">Add Item</a>`
29740  */
29741 var htmlAnchorDirective = valueFn({
29742   restrict: 'E',
29743   compile: function(element, attr) {
29744     if (!attr.href && !attr.xlinkHref) {
29745       return function(scope, element) {
29746         // If the linked element is not an anchor tag anymore, do nothing
29747         if (element[0].nodeName.toLowerCase() !== 'a') return;
29748
29749         // SVGAElement does not use the href attribute, but rather the 'xlinkHref' attribute.
29750         var href = toString.call(element.prop('href')) === '[object SVGAnimatedString]' ?
29751                    'xlink:href' : 'href';
29752         element.on('click', function(event) {
29753           // if we have no href url, then don't navigate anywhere.
29754           if (!element.attr(href)) {
29755             event.preventDefault();
29756           }
29757         });
29758       };
29759     }
29760   }
29761 });
29762
29763 /**
29764  * @ngdoc directive
29765  * @name ngHref
29766  * @restrict A
29767  * @priority 99
29768  *
29769  * @description
29770  * Using Angular markup like `{{hash}}` in an href attribute will
29771  * make the link go to the wrong URL if the user clicks it before
29772  * Angular has a chance to replace the `{{hash}}` markup with its
29773  * value. Until Angular replaces the markup the link will be broken
29774  * and will most likely return a 404 error. The `ngHref` directive
29775  * solves this problem.
29776  *
29777  * The wrong way to write it:
29778  * ```html
29779  * <a href="http://www.gravatar.com/avatar/{{hash}}">link1</a>
29780  * ```
29781  *
29782  * The correct way to write it:
29783  * ```html
29784  * <a ng-href="http://www.gravatar.com/avatar/{{hash}}">link1</a>
29785  * ```
29786  *
29787  * @element A
29788  * @param {template} ngHref any string which can contain `{{}}` markup.
29789  *
29790  * @example
29791  * This example shows various combinations of `href`, `ng-href` and `ng-click` attributes
29792  * in links and their different behaviors:
29793     <example>
29794       <file name="index.html">
29795         <input ng-model="value" /><br />
29796         <a id="link-1" href ng-click="value = 1">link 1</a> (link, don't reload)<br />
29797         <a id="link-2" href="" ng-click="value = 2">link 2</a> (link, don't reload)<br />
29798         <a id="link-3" ng-href="/{{'123'}}">link 3</a> (link, reload!)<br />
29799         <a id="link-4" href="" name="xx" ng-click="value = 4">anchor</a> (link, don't reload)<br />
29800         <a id="link-5" name="xxx" ng-click="value = 5">anchor</a> (no link)<br />
29801         <a id="link-6" ng-href="{{value}}">link</a> (link, change location)
29802       </file>
29803       <file name="protractor.js" type="protractor">
29804         it('should execute ng-click but not reload when href without value', function() {
29805           element(by.id('link-1')).click();
29806           expect(element(by.model('value')).getAttribute('value')).toEqual('1');
29807           expect(element(by.id('link-1')).getAttribute('href')).toBe('');
29808         });
29809
29810         it('should execute ng-click but not reload when href empty string', function() {
29811           element(by.id('link-2')).click();
29812           expect(element(by.model('value')).getAttribute('value')).toEqual('2');
29813           expect(element(by.id('link-2')).getAttribute('href')).toBe('');
29814         });
29815
29816         it('should execute ng-click and change url when ng-href specified', function() {
29817           expect(element(by.id('link-3')).getAttribute('href')).toMatch(/\/123$/);
29818
29819           element(by.id('link-3')).click();
29820
29821           // At this point, we navigate away from an Angular page, so we need
29822           // to use browser.driver to get the base webdriver.
29823
29824           browser.wait(function() {
29825             return browser.driver.getCurrentUrl().then(function(url) {
29826               return url.match(/\/123$/);
29827             });
29828           }, 5000, 'page should navigate to /123');
29829         });
29830
29831         it('should execute ng-click but not reload when href empty string and name specified', function() {
29832           element(by.id('link-4')).click();
29833           expect(element(by.model('value')).getAttribute('value')).toEqual('4');
29834           expect(element(by.id('link-4')).getAttribute('href')).toBe('');
29835         });
29836
29837         it('should execute ng-click but not reload when no href but name specified', function() {
29838           element(by.id('link-5')).click();
29839           expect(element(by.model('value')).getAttribute('value')).toEqual('5');
29840           expect(element(by.id('link-5')).getAttribute('href')).toBe(null);
29841         });
29842
29843         it('should only change url when only ng-href', function() {
29844           element(by.model('value')).clear();
29845           element(by.model('value')).sendKeys('6');
29846           expect(element(by.id('link-6')).getAttribute('href')).toMatch(/\/6$/);
29847
29848           element(by.id('link-6')).click();
29849
29850           // At this point, we navigate away from an Angular page, so we need
29851           // to use browser.driver to get the base webdriver.
29852           browser.wait(function() {
29853             return browser.driver.getCurrentUrl().then(function(url) {
29854               return url.match(/\/6$/);
29855             });
29856           }, 5000, 'page should navigate to /6');
29857         });
29858       </file>
29859     </example>
29860  */
29861
29862 /**
29863  * @ngdoc directive
29864  * @name ngSrc
29865  * @restrict A
29866  * @priority 99
29867  *
29868  * @description
29869  * Using Angular markup like `{{hash}}` in a `src` attribute doesn't
29870  * work right: The browser will fetch from the URL with the literal
29871  * text `{{hash}}` until Angular replaces the expression inside
29872  * `{{hash}}`. The `ngSrc` directive solves this problem.
29873  *
29874  * The buggy way to write it:
29875  * ```html
29876  * <img src="http://www.gravatar.com/avatar/{{hash}}" alt="Description"/>
29877  * ```
29878  *
29879  * The correct way to write it:
29880  * ```html
29881  * <img ng-src="http://www.gravatar.com/avatar/{{hash}}" alt="Description" />
29882  * ```
29883  *
29884  * @element IMG
29885  * @param {template} ngSrc any string which can contain `{{}}` markup.
29886  */
29887
29888 /**
29889  * @ngdoc directive
29890  * @name ngSrcset
29891  * @restrict A
29892  * @priority 99
29893  *
29894  * @description
29895  * Using Angular markup like `{{hash}}` in a `srcset` attribute doesn't
29896  * work right: The browser will fetch from the URL with the literal
29897  * text `{{hash}}` until Angular replaces the expression inside
29898  * `{{hash}}`. The `ngSrcset` directive solves this problem.
29899  *
29900  * The buggy way to write it:
29901  * ```html
29902  * <img srcset="http://www.gravatar.com/avatar/{{hash}} 2x" alt="Description"/>
29903  * ```
29904  *
29905  * The correct way to write it:
29906  * ```html
29907  * <img ng-srcset="http://www.gravatar.com/avatar/{{hash}} 2x" alt="Description" />
29908  * ```
29909  *
29910  * @element IMG
29911  * @param {template} ngSrcset any string which can contain `{{}}` markup.
29912  */
29913
29914 /**
29915  * @ngdoc directive
29916  * @name ngDisabled
29917  * @restrict A
29918  * @priority 100
29919  *
29920  * @description
29921  *
29922  * This directive sets the `disabled` attribute on the element if the
29923  * {@link guide/expression expression} inside `ngDisabled` evaluates to truthy.
29924  *
29925  * A special directive is necessary because we cannot use interpolation inside the `disabled`
29926  * attribute. See the {@link guide/interpolation interpolation guide} for more info.
29927  *
29928  * @example
29929     <example>
29930       <file name="index.html">
29931         <label>Click me to toggle: <input type="checkbox" ng-model="checked"></label><br/>
29932         <button ng-model="button" ng-disabled="checked">Button</button>
29933       </file>
29934       <file name="protractor.js" type="protractor">
29935         it('should toggle button', function() {
29936           expect(element(by.css('button')).getAttribute('disabled')).toBeFalsy();
29937           element(by.model('checked')).click();
29938           expect(element(by.css('button')).getAttribute('disabled')).toBeTruthy();
29939         });
29940       </file>
29941     </example>
29942  *
29943  * @element INPUT
29944  * @param {expression} ngDisabled If the {@link guide/expression expression} is truthy,
29945  *     then the `disabled` attribute will be set on the element
29946  */
29947
29948
29949 /**
29950  * @ngdoc directive
29951  * @name ngChecked
29952  * @restrict A
29953  * @priority 100
29954  *
29955  * @description
29956  * Sets the `checked` attribute on the element, if the expression inside `ngChecked` is truthy.
29957  *
29958  * Note that this directive should not be used together with {@link ngModel `ngModel`},
29959  * as this can lead to unexpected behavior.
29960  *
29961  * A special directive is necessary because we cannot use interpolation inside the `checked`
29962  * attribute. See the {@link guide/interpolation interpolation guide} for more info.
29963  *
29964  * @example
29965     <example>
29966       <file name="index.html">
29967         <label>Check me to check both: <input type="checkbox" ng-model="master"></label><br/>
29968         <input id="checkSlave" type="checkbox" ng-checked="master" aria-label="Slave input">
29969       </file>
29970       <file name="protractor.js" type="protractor">
29971         it('should check both checkBoxes', function() {
29972           expect(element(by.id('checkSlave')).getAttribute('checked')).toBeFalsy();
29973           element(by.model('master')).click();
29974           expect(element(by.id('checkSlave')).getAttribute('checked')).toBeTruthy();
29975         });
29976       </file>
29977     </example>
29978  *
29979  * @element INPUT
29980  * @param {expression} ngChecked If the {@link guide/expression expression} is truthy,
29981  *     then the `checked` attribute will be set on the element
29982  */
29983
29984
29985 /**
29986  * @ngdoc directive
29987  * @name ngReadonly
29988  * @restrict A
29989  * @priority 100
29990  *
29991  * @description
29992  *
29993  * Sets the `readOnly` attribute on the element, if the expression inside `ngReadonly` is truthy.
29994  *
29995  * A special directive is necessary because we cannot use interpolation inside the `readOnly`
29996  * attribute. See the {@link guide/interpolation interpolation guide} for more info.
29997  *
29998  * @example
29999     <example>
30000       <file name="index.html">
30001         <label>Check me to make text readonly: <input type="checkbox" ng-model="checked"></label><br/>
30002         <input type="text" ng-readonly="checked" value="I'm Angular" aria-label="Readonly field" />
30003       </file>
30004       <file name="protractor.js" type="protractor">
30005         it('should toggle readonly attr', function() {
30006           expect(element(by.css('[type="text"]')).getAttribute('readonly')).toBeFalsy();
30007           element(by.model('checked')).click();
30008           expect(element(by.css('[type="text"]')).getAttribute('readonly')).toBeTruthy();
30009         });
30010       </file>
30011     </example>
30012  *
30013  * @element INPUT
30014  * @param {expression} ngReadonly If the {@link guide/expression expression} is truthy,
30015  *     then special attribute "readonly" will be set on the element
30016  */
30017
30018
30019 /**
30020  * @ngdoc directive
30021  * @name ngSelected
30022  * @restrict A
30023  * @priority 100
30024  *
30025  * @description
30026  *
30027  * Sets the `selected` attribute on the element, if the expression inside `ngSelected` is truthy.
30028  *
30029  * A special directive is necessary because we cannot use interpolation inside the `selected`
30030  * attribute. See the {@link guide/interpolation interpolation guide} for more info.
30031  *
30032  * @example
30033     <example>
30034       <file name="index.html">
30035         <label>Check me to select: <input type="checkbox" ng-model="selected"></label><br/>
30036         <select aria-label="ngSelected demo">
30037           <option>Hello!</option>
30038           <option id="greet" ng-selected="selected">Greetings!</option>
30039         </select>
30040       </file>
30041       <file name="protractor.js" type="protractor">
30042         it('should select Greetings!', function() {
30043           expect(element(by.id('greet')).getAttribute('selected')).toBeFalsy();
30044           element(by.model('selected')).click();
30045           expect(element(by.id('greet')).getAttribute('selected')).toBeTruthy();
30046         });
30047       </file>
30048     </example>
30049  *
30050  * @element OPTION
30051  * @param {expression} ngSelected If the {@link guide/expression expression} is truthy,
30052  *     then special attribute "selected" will be set on the element
30053  */
30054
30055 /**
30056  * @ngdoc directive
30057  * @name ngOpen
30058  * @restrict A
30059  * @priority 100
30060  *
30061  * @description
30062  *
30063  * Sets the `open` attribute on the element, if the expression inside `ngOpen` is truthy.
30064  *
30065  * A special directive is necessary because we cannot use interpolation inside the `open`
30066  * attribute. See the {@link guide/interpolation interpolation guide} for more info.
30067  *
30068  * @example
30069      <example>
30070        <file name="index.html">
30071          <label>Check me check multiple: <input type="checkbox" ng-model="open"></label><br/>
30072          <details id="details" ng-open="open">
30073             <summary>Show/Hide me</summary>
30074          </details>
30075        </file>
30076        <file name="protractor.js" type="protractor">
30077          it('should toggle open', function() {
30078            expect(element(by.id('details')).getAttribute('open')).toBeFalsy();
30079            element(by.model('open')).click();
30080            expect(element(by.id('details')).getAttribute('open')).toBeTruthy();
30081          });
30082        </file>
30083      </example>
30084  *
30085  * @element DETAILS
30086  * @param {expression} ngOpen If the {@link guide/expression expression} is truthy,
30087  *     then special attribute "open" will be set on the element
30088  */
30089
30090 var ngAttributeAliasDirectives = {};
30091
30092 // boolean attrs are evaluated
30093 forEach(BOOLEAN_ATTR, function(propName, attrName) {
30094   // binding to multiple is not supported
30095   if (propName == "multiple") return;
30096
30097   function defaultLinkFn(scope, element, attr) {
30098     scope.$watch(attr[normalized], function ngBooleanAttrWatchAction(value) {
30099       attr.$set(attrName, !!value);
30100     });
30101   }
30102
30103   var normalized = directiveNormalize('ng-' + attrName);
30104   var linkFn = defaultLinkFn;
30105
30106   if (propName === 'checked') {
30107     linkFn = function(scope, element, attr) {
30108       // ensuring ngChecked doesn't interfere with ngModel when both are set on the same input
30109       if (attr.ngModel !== attr[normalized]) {
30110         defaultLinkFn(scope, element, attr);
30111       }
30112     };
30113   }
30114
30115   ngAttributeAliasDirectives[normalized] = function() {
30116     return {
30117       restrict: 'A',
30118       priority: 100,
30119       link: linkFn
30120     };
30121   };
30122 });
30123
30124 // aliased input attrs are evaluated
30125 forEach(ALIASED_ATTR, function(htmlAttr, ngAttr) {
30126   ngAttributeAliasDirectives[ngAttr] = function() {
30127     return {
30128       priority: 100,
30129       link: function(scope, element, attr) {
30130         //special case ngPattern when a literal regular expression value
30131         //is used as the expression (this way we don't have to watch anything).
30132         if (ngAttr === "ngPattern" && attr.ngPattern.charAt(0) == "/") {
30133           var match = attr.ngPattern.match(REGEX_STRING_REGEXP);
30134           if (match) {
30135             attr.$set("ngPattern", new RegExp(match[1], match[2]));
30136             return;
30137           }
30138         }
30139
30140         scope.$watch(attr[ngAttr], function ngAttrAliasWatchAction(value) {
30141           attr.$set(ngAttr, value);
30142         });
30143       }
30144     };
30145   };
30146 });
30147
30148 // ng-src, ng-srcset, ng-href are interpolated
30149 forEach(['src', 'srcset', 'href'], function(attrName) {
30150   var normalized = directiveNormalize('ng-' + attrName);
30151   ngAttributeAliasDirectives[normalized] = function() {
30152     return {
30153       priority: 99, // it needs to run after the attributes are interpolated
30154       link: function(scope, element, attr) {
30155         var propName = attrName,
30156             name = attrName;
30157
30158         if (attrName === 'href' &&
30159             toString.call(element.prop('href')) === '[object SVGAnimatedString]') {
30160           name = 'xlinkHref';
30161           attr.$attr[name] = 'xlink:href';
30162           propName = null;
30163         }
30164
30165         attr.$observe(normalized, function(value) {
30166           if (!value) {
30167             if (attrName === 'href') {
30168               attr.$set(name, null);
30169             }
30170             return;
30171           }
30172
30173           attr.$set(name, value);
30174
30175           // on IE, if "ng:src" directive declaration is used and "src" attribute doesn't exist
30176           // then calling element.setAttribute('src', 'foo') doesn't do anything, so we need
30177           // to set the property as well to achieve the desired effect.
30178           // we use attr[attrName] value since $set can sanitize the url.
30179           if (msie && propName) element.prop(propName, attr[name]);
30180         });
30181       }
30182     };
30183   };
30184 });
30185
30186 /* global -nullFormCtrl, -SUBMITTED_CLASS, addSetValidityMethod: true
30187  */
30188 var nullFormCtrl = {
30189   $addControl: noop,
30190   $$renameControl: nullFormRenameControl,
30191   $removeControl: noop,
30192   $setValidity: noop,
30193   $setDirty: noop,
30194   $setPristine: noop,
30195   $setSubmitted: noop
30196 },
30197 SUBMITTED_CLASS = 'ng-submitted';
30198
30199 function nullFormRenameControl(control, name) {
30200   control.$name = name;
30201 }
30202
30203 /**
30204  * @ngdoc type
30205  * @name form.FormController
30206  *
30207  * @property {boolean} $pristine True if user has not interacted with the form yet.
30208  * @property {boolean} $dirty True if user has already interacted with the form.
30209  * @property {boolean} $valid True if all of the containing forms and controls are valid.
30210  * @property {boolean} $invalid True if at least one containing control or form is invalid.
30211  * @property {boolean} $pending True if at least one containing control or form is pending.
30212  * @property {boolean} $submitted True if user has submitted the form even if its invalid.
30213  *
30214  * @property {Object} $error Is an object hash, containing references to controls or
30215  *  forms with failing validators, where:
30216  *
30217  *  - keys are validation tokens (error names),
30218  *  - values are arrays of controls or forms that have a failing validator for given error name.
30219  *
30220  *  Built-in validation tokens:
30221  *
30222  *  - `email`
30223  *  - `max`
30224  *  - `maxlength`
30225  *  - `min`
30226  *  - `minlength`
30227  *  - `number`
30228  *  - `pattern`
30229  *  - `required`
30230  *  - `url`
30231  *  - `date`
30232  *  - `datetimelocal`
30233  *  - `time`
30234  *  - `week`
30235  *  - `month`
30236  *
30237  * @description
30238  * `FormController` keeps track of all its controls and nested forms as well as the state of them,
30239  * such as being valid/invalid or dirty/pristine.
30240  *
30241  * Each {@link ng.directive:form form} directive creates an instance
30242  * of `FormController`.
30243  *
30244  */
30245 //asks for $scope to fool the BC controller module
30246 FormController.$inject = ['$element', '$attrs', '$scope', '$animate', '$interpolate'];
30247 function FormController(element, attrs, $scope, $animate, $interpolate) {
30248   var form = this,
30249       controls = [];
30250
30251   // init state
30252   form.$error = {};
30253   form.$$success = {};
30254   form.$pending = undefined;
30255   form.$name = $interpolate(attrs.name || attrs.ngForm || '')($scope);
30256   form.$dirty = false;
30257   form.$pristine = true;
30258   form.$valid = true;
30259   form.$invalid = false;
30260   form.$submitted = false;
30261   form.$$parentForm = nullFormCtrl;
30262
30263   /**
30264    * @ngdoc method
30265    * @name form.FormController#$rollbackViewValue
30266    *
30267    * @description
30268    * Rollback all form controls pending updates to the `$modelValue`.
30269    *
30270    * Updates may be pending by a debounced event or because the input is waiting for a some future
30271    * event defined in `ng-model-options`. This method is typically needed by the reset button of
30272    * a form that uses `ng-model-options` to pend updates.
30273    */
30274   form.$rollbackViewValue = function() {
30275     forEach(controls, function(control) {
30276       control.$rollbackViewValue();
30277     });
30278   };
30279
30280   /**
30281    * @ngdoc method
30282    * @name form.FormController#$commitViewValue
30283    *
30284    * @description
30285    * Commit all form controls pending updates to the `$modelValue`.
30286    *
30287    * Updates may be pending by a debounced event or because the input is waiting for a some future
30288    * event defined in `ng-model-options`. This method is rarely needed as `NgModelController`
30289    * usually handles calling this in response to input events.
30290    */
30291   form.$commitViewValue = function() {
30292     forEach(controls, function(control) {
30293       control.$commitViewValue();
30294     });
30295   };
30296
30297   /**
30298    * @ngdoc method
30299    * @name form.FormController#$addControl
30300    * @param {object} control control object, either a {@link form.FormController} or an
30301    * {@link ngModel.NgModelController}
30302    *
30303    * @description
30304    * Register a control with the form. Input elements using ngModelController do this automatically
30305    * when they are linked.
30306    *
30307    * Note that the current state of the control will not be reflected on the new parent form. This
30308    * is not an issue with normal use, as freshly compiled and linked controls are in a `$pristine`
30309    * state.
30310    *
30311    * However, if the method is used programmatically, for example by adding dynamically created controls,
30312    * or controls that have been previously removed without destroying their corresponding DOM element,
30313    * it's the developers responsibility to make sure the current state propagates to the parent form.
30314    *
30315    * For example, if an input control is added that is already `$dirty` and has `$error` properties,
30316    * calling `$setDirty()` and `$validate()` afterwards will propagate the state to the parent form.
30317    */
30318   form.$addControl = function(control) {
30319     // Breaking change - before, inputs whose name was "hasOwnProperty" were quietly ignored
30320     // and not added to the scope.  Now we throw an error.
30321     assertNotHasOwnProperty(control.$name, 'input');
30322     controls.push(control);
30323
30324     if (control.$name) {
30325       form[control.$name] = control;
30326     }
30327
30328     control.$$parentForm = form;
30329   };
30330
30331   // Private API: rename a form control
30332   form.$$renameControl = function(control, newName) {
30333     var oldName = control.$name;
30334
30335     if (form[oldName] === control) {
30336       delete form[oldName];
30337     }
30338     form[newName] = control;
30339     control.$name = newName;
30340   };
30341
30342   /**
30343    * @ngdoc method
30344    * @name form.FormController#$removeControl
30345    * @param {object} control control object, either a {@link form.FormController} or an
30346    * {@link ngModel.NgModelController}
30347    *
30348    * @description
30349    * Deregister a control from the form.
30350    *
30351    * Input elements using ngModelController do this automatically when they are destroyed.
30352    *
30353    * Note that only the removed control's validation state (`$errors`etc.) will be removed from the
30354    * form. `$dirty`, `$submitted` states will not be changed, because the expected behavior can be
30355    * different from case to case. For example, removing the only `$dirty` control from a form may or
30356    * may not mean that the form is still `$dirty`.
30357    */
30358   form.$removeControl = function(control) {
30359     if (control.$name && form[control.$name] === control) {
30360       delete form[control.$name];
30361     }
30362     forEach(form.$pending, function(value, name) {
30363       form.$setValidity(name, null, control);
30364     });
30365     forEach(form.$error, function(value, name) {
30366       form.$setValidity(name, null, control);
30367     });
30368     forEach(form.$$success, function(value, name) {
30369       form.$setValidity(name, null, control);
30370     });
30371
30372     arrayRemove(controls, control);
30373     control.$$parentForm = nullFormCtrl;
30374   };
30375
30376
30377   /**
30378    * @ngdoc method
30379    * @name form.FormController#$setValidity
30380    *
30381    * @description
30382    * Sets the validity of a form control.
30383    *
30384    * This method will also propagate to parent forms.
30385    */
30386   addSetValidityMethod({
30387     ctrl: this,
30388     $element: element,
30389     set: function(object, property, controller) {
30390       var list = object[property];
30391       if (!list) {
30392         object[property] = [controller];
30393       } else {
30394         var index = list.indexOf(controller);
30395         if (index === -1) {
30396           list.push(controller);
30397         }
30398       }
30399     },
30400     unset: function(object, property, controller) {
30401       var list = object[property];
30402       if (!list) {
30403         return;
30404       }
30405       arrayRemove(list, controller);
30406       if (list.length === 0) {
30407         delete object[property];
30408       }
30409     },
30410     $animate: $animate
30411   });
30412
30413   /**
30414    * @ngdoc method
30415    * @name form.FormController#$setDirty
30416    *
30417    * @description
30418    * Sets the form to a dirty state.
30419    *
30420    * This method can be called to add the 'ng-dirty' class and set the form to a dirty
30421    * state (ng-dirty class). This method will also propagate to parent forms.
30422    */
30423   form.$setDirty = function() {
30424     $animate.removeClass(element, PRISTINE_CLASS);
30425     $animate.addClass(element, DIRTY_CLASS);
30426     form.$dirty = true;
30427     form.$pristine = false;
30428     form.$$parentForm.$setDirty();
30429   };
30430
30431   /**
30432    * @ngdoc method
30433    * @name form.FormController#$setPristine
30434    *
30435    * @description
30436    * Sets the form to its pristine state.
30437    *
30438    * This method can be called to remove the 'ng-dirty' class and set the form to its pristine
30439    * state (ng-pristine class). This method will also propagate to all the controls contained
30440    * in this form.
30441    *
30442    * Setting a form back to a pristine state is often useful when we want to 'reuse' a form after
30443    * saving or resetting it.
30444    */
30445   form.$setPristine = function() {
30446     $animate.setClass(element, PRISTINE_CLASS, DIRTY_CLASS + ' ' + SUBMITTED_CLASS);
30447     form.$dirty = false;
30448     form.$pristine = true;
30449     form.$submitted = false;
30450     forEach(controls, function(control) {
30451       control.$setPristine();
30452     });
30453   };
30454
30455   /**
30456    * @ngdoc method
30457    * @name form.FormController#$setUntouched
30458    *
30459    * @description
30460    * Sets the form to its untouched state.
30461    *
30462    * This method can be called to remove the 'ng-touched' class and set the form controls to their
30463    * untouched state (ng-untouched class).
30464    *
30465    * Setting a form controls back to their untouched state is often useful when setting the form
30466    * back to its pristine state.
30467    */
30468   form.$setUntouched = function() {
30469     forEach(controls, function(control) {
30470       control.$setUntouched();
30471     });
30472   };
30473
30474   /**
30475    * @ngdoc method
30476    * @name form.FormController#$setSubmitted
30477    *
30478    * @description
30479    * Sets the form to its submitted state.
30480    */
30481   form.$setSubmitted = function() {
30482     $animate.addClass(element, SUBMITTED_CLASS);
30483     form.$submitted = true;
30484     form.$$parentForm.$setSubmitted();
30485   };
30486 }
30487
30488 /**
30489  * @ngdoc directive
30490  * @name ngForm
30491  * @restrict EAC
30492  *
30493  * @description
30494  * Nestable alias of {@link ng.directive:form `form`} directive. HTML
30495  * does not allow nesting of form elements. It is useful to nest forms, for example if the validity of a
30496  * sub-group of controls needs to be determined.
30497  *
30498  * Note: the purpose of `ngForm` is to group controls,
30499  * but not to be a replacement for the `<form>` tag with all of its capabilities
30500  * (e.g. posting to the server, ...).
30501  *
30502  * @param {string=} ngForm|name Name of the form. If specified, the form controller will be published into
30503  *                       related scope, under this name.
30504  *
30505  */
30506
30507  /**
30508  * @ngdoc directive
30509  * @name form
30510  * @restrict E
30511  *
30512  * @description
30513  * Directive that instantiates
30514  * {@link form.FormController FormController}.
30515  *
30516  * If the `name` attribute is specified, the form controller is published onto the current scope under
30517  * this name.
30518  *
30519  * # Alias: {@link ng.directive:ngForm `ngForm`}
30520  *
30521  * In Angular, forms can be nested. This means that the outer form is valid when all of the child
30522  * forms are valid as well. However, browsers do not allow nesting of `<form>` elements, so
30523  * Angular provides the {@link ng.directive:ngForm `ngForm`} directive, which behaves identically to
30524  * `form` but can be nested. Nested forms can be useful, for example, if the validity of a sub-group
30525  * of controls needs to be determined.
30526  *
30527  * # CSS classes
30528  *  - `ng-valid` is set if the form is valid.
30529  *  - `ng-invalid` is set if the form is invalid.
30530  *  - `ng-pending` is set if the form is pending.
30531  *  - `ng-pristine` is set if the form is pristine.
30532  *  - `ng-dirty` is set if the form is dirty.
30533  *  - `ng-submitted` is set if the form was submitted.
30534  *
30535  * Keep in mind that ngAnimate can detect each of these classes when added and removed.
30536  *
30537  *
30538  * # Submitting a form and preventing the default action
30539  *
30540  * Since the role of forms in client-side Angular applications is different than in classical
30541  * roundtrip apps, it is desirable for the browser not to translate the form submission into a full
30542  * page reload that sends the data to the server. Instead some javascript logic should be triggered
30543  * to handle the form submission in an application-specific way.
30544  *
30545  * For this reason, Angular prevents the default action (form submission to the server) unless the
30546  * `<form>` element has an `action` attribute specified.
30547  *
30548  * You can use one of the following two ways to specify what javascript method should be called when
30549  * a form is submitted:
30550  *
30551  * - {@link ng.directive:ngSubmit ngSubmit} directive on the form element
30552  * - {@link ng.directive:ngClick ngClick} directive on the first
30553   *  button or input field of type submit (input[type=submit])
30554  *
30555  * To prevent double execution of the handler, use only one of the {@link ng.directive:ngSubmit ngSubmit}
30556  * or {@link ng.directive:ngClick ngClick} directives.
30557  * This is because of the following form submission rules in the HTML specification:
30558  *
30559  * - If a form has only one input field then hitting enter in this field triggers form submit
30560  * (`ngSubmit`)
30561  * - if a form has 2+ input fields and no buttons or input[type=submit] then hitting enter
30562  * doesn't trigger submit
30563  * - if a form has one or more input fields and one or more buttons or input[type=submit] then
30564  * hitting enter in any of the input fields will trigger the click handler on the *first* button or
30565  * input[type=submit] (`ngClick`) *and* a submit handler on the enclosing form (`ngSubmit`)
30566  *
30567  * Any pending `ngModelOptions` changes will take place immediately when an enclosing form is
30568  * submitted. Note that `ngClick` events will occur before the model is updated. Use `ngSubmit`
30569  * to have access to the updated model.
30570  *
30571  * ## Animation Hooks
30572  *
30573  * Animations in ngForm are triggered when any of the associated CSS classes are added and removed.
30574  * These classes are: `.ng-pristine`, `.ng-dirty`, `.ng-invalid` and `.ng-valid` as well as any
30575  * other validations that are performed within the form. Animations in ngForm are similar to how
30576  * they work in ngClass and animations can be hooked into using CSS transitions, keyframes as well
30577  * as JS animations.
30578  *
30579  * The following example shows a simple way to utilize CSS transitions to style a form element
30580  * that has been rendered as invalid after it has been validated:
30581  *
30582  * <pre>
30583  * //be sure to include ngAnimate as a module to hook into more
30584  * //advanced animations
30585  * .my-form {
30586  *   transition:0.5s linear all;
30587  *   background: white;
30588  * }
30589  * .my-form.ng-invalid {
30590  *   background: red;
30591  *   color:white;
30592  * }
30593  * </pre>
30594  *
30595  * @example
30596     <example deps="angular-animate.js" animations="true" fixBase="true" module="formExample">
30597       <file name="index.html">
30598        <script>
30599          angular.module('formExample', [])
30600            .controller('FormController', ['$scope', function($scope) {
30601              $scope.userType = 'guest';
30602            }]);
30603        </script>
30604        <style>
30605         .my-form {
30606           transition:all linear 0.5s;
30607           background: transparent;
30608         }
30609         .my-form.ng-invalid {
30610           background: red;
30611         }
30612        </style>
30613        <form name="myForm" ng-controller="FormController" class="my-form">
30614          userType: <input name="input" ng-model="userType" required>
30615          <span class="error" ng-show="myForm.input.$error.required">Required!</span><br>
30616          <code>userType = {{userType}}</code><br>
30617          <code>myForm.input.$valid = {{myForm.input.$valid}}</code><br>
30618          <code>myForm.input.$error = {{myForm.input.$error}}</code><br>
30619          <code>myForm.$valid = {{myForm.$valid}}</code><br>
30620          <code>myForm.$error.required = {{!!myForm.$error.required}}</code><br>
30621         </form>
30622       </file>
30623       <file name="protractor.js" type="protractor">
30624         it('should initialize to model', function() {
30625           var userType = element(by.binding('userType'));
30626           var valid = element(by.binding('myForm.input.$valid'));
30627
30628           expect(userType.getText()).toContain('guest');
30629           expect(valid.getText()).toContain('true');
30630         });
30631
30632         it('should be invalid if empty', function() {
30633           var userType = element(by.binding('userType'));
30634           var valid = element(by.binding('myForm.input.$valid'));
30635           var userInput = element(by.model('userType'));
30636
30637           userInput.clear();
30638           userInput.sendKeys('');
30639
30640           expect(userType.getText()).toEqual('userType =');
30641           expect(valid.getText()).toContain('false');
30642         });
30643       </file>
30644     </example>
30645  *
30646  * @param {string=} name Name of the form. If specified, the form controller will be published into
30647  *                       related scope, under this name.
30648  */
30649 var formDirectiveFactory = function(isNgForm) {
30650   return ['$timeout', '$parse', function($timeout, $parse) {
30651     var formDirective = {
30652       name: 'form',
30653       restrict: isNgForm ? 'EAC' : 'E',
30654       require: ['form', '^^?form'], //first is the form's own ctrl, second is an optional parent form
30655       controller: FormController,
30656       compile: function ngFormCompile(formElement, attr) {
30657         // Setup initial state of the control
30658         formElement.addClass(PRISTINE_CLASS).addClass(VALID_CLASS);
30659
30660         var nameAttr = attr.name ? 'name' : (isNgForm && attr.ngForm ? 'ngForm' : false);
30661
30662         return {
30663           pre: function ngFormPreLink(scope, formElement, attr, ctrls) {
30664             var controller = ctrls[0];
30665
30666             // if `action` attr is not present on the form, prevent the default action (submission)
30667             if (!('action' in attr)) {
30668               // we can't use jq events because if a form is destroyed during submission the default
30669               // action is not prevented. see #1238
30670               //
30671               // IE 9 is not affected because it doesn't fire a submit event and try to do a full
30672               // page reload if the form was destroyed by submission of the form via a click handler
30673               // on a button in the form. Looks like an IE9 specific bug.
30674               var handleFormSubmission = function(event) {
30675                 scope.$apply(function() {
30676                   controller.$commitViewValue();
30677                   controller.$setSubmitted();
30678                 });
30679
30680                 event.preventDefault();
30681               };
30682
30683               addEventListenerFn(formElement[0], 'submit', handleFormSubmission);
30684
30685               // unregister the preventDefault listener so that we don't not leak memory but in a
30686               // way that will achieve the prevention of the default action.
30687               formElement.on('$destroy', function() {
30688                 $timeout(function() {
30689                   removeEventListenerFn(formElement[0], 'submit', handleFormSubmission);
30690                 }, 0, false);
30691               });
30692             }
30693
30694             var parentFormCtrl = ctrls[1] || controller.$$parentForm;
30695             parentFormCtrl.$addControl(controller);
30696
30697             var setter = nameAttr ? getSetter(controller.$name) : noop;
30698
30699             if (nameAttr) {
30700               setter(scope, controller);
30701               attr.$observe(nameAttr, function(newValue) {
30702                 if (controller.$name === newValue) return;
30703                 setter(scope, undefined);
30704                 controller.$$parentForm.$$renameControl(controller, newValue);
30705                 setter = getSetter(controller.$name);
30706                 setter(scope, controller);
30707               });
30708             }
30709             formElement.on('$destroy', function() {
30710               controller.$$parentForm.$removeControl(controller);
30711               setter(scope, undefined);
30712               extend(controller, nullFormCtrl); //stop propagating child destruction handlers upwards
30713             });
30714           }
30715         };
30716       }
30717     };
30718
30719     return formDirective;
30720
30721     function getSetter(expression) {
30722       if (expression === '') {
30723         //create an assignable expression, so forms with an empty name can be renamed later
30724         return $parse('this[""]').assign;
30725       }
30726       return $parse(expression).assign || noop;
30727     }
30728   }];
30729 };
30730
30731 var formDirective = formDirectiveFactory();
30732 var ngFormDirective = formDirectiveFactory(true);
30733
30734 /* global VALID_CLASS: false,
30735   INVALID_CLASS: false,
30736   PRISTINE_CLASS: false,
30737   DIRTY_CLASS: false,
30738   UNTOUCHED_CLASS: false,
30739   TOUCHED_CLASS: false,
30740   ngModelMinErr: false,
30741 */
30742
30743 // Regex code is obtained from SO: https://stackoverflow.com/questions/3143070/javascript-regex-iso-datetime#answer-3143231
30744 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)/;
30745 // See valid URLs in RFC3987 (http://tools.ietf.org/html/rfc3987)
30746 // Note: We are being more lenient, because browsers are too.
30747 //   1. Scheme
30748 //   2. Slashes
30749 //   3. Username
30750 //   4. Password
30751 //   5. Hostname
30752 //   6. Port
30753 //   7. Path
30754 //   8. Query
30755 //   9. Fragment
30756 //                 1111111111111111 222   333333    44444        555555555555555555555555    666     77777777     8888888     999
30757 var URL_REGEXP = /^[a-z][a-z\d.+-]*:\/*(?:[^:@]+(?::[^@]+)?@)?(?:[^\s:/?#]+|\[[a-f\d:]+\])(?::\d+)?(?:\/[^?#]*)?(?:\?[^#]*)?(?:#.*)?$/i;
30758 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;
30759 var NUMBER_REGEXP = /^\s*(\-|\+)?(\d+|(\d*(\.\d*)))([eE][+-]?\d+)?\s*$/;
30760 var DATE_REGEXP = /^(\d{4})-(\d{2})-(\d{2})$/;
30761 var DATETIMELOCAL_REGEXP = /^(\d{4})-(\d\d)-(\d\d)T(\d\d):(\d\d)(?::(\d\d)(\.\d{1,3})?)?$/;
30762 var WEEK_REGEXP = /^(\d{4})-W(\d\d)$/;
30763 var MONTH_REGEXP = /^(\d{4})-(\d\d)$/;
30764 var TIME_REGEXP = /^(\d\d):(\d\d)(?::(\d\d)(\.\d{1,3})?)?$/;
30765
30766 var inputType = {
30767
30768   /**
30769    * @ngdoc input
30770    * @name input[text]
30771    *
30772    * @description
30773    * Standard HTML text input with angular data binding, inherited by most of the `input` elements.
30774    *
30775    *
30776    * @param {string} ngModel Assignable angular expression to data-bind to.
30777    * @param {string=} name Property name of the form under which the control is published.
30778    * @param {string=} required Adds `required` validation error key if the value is not entered.
30779    * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
30780    *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
30781    *    `required` when you want to data-bind to the `required` attribute.
30782    * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
30783    *    minlength.
30784    * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
30785    *    maxlength. Setting the attribute to a negative or non-numeric value, allows view values of
30786    *    any length.
30787    * @param {string=} pattern Similar to `ngPattern` except that the attribute value is the actual string
30788    *    that contains the regular expression body that will be converted to a regular expression
30789    *    as in the ngPattern directive.
30790    * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel {@link ngModel.NgModelController#$viewValue $viewValue}
30791    *    does not match a RegExp found by evaluating the Angular expression given in the attribute value.
30792    *    If the expression evaluates to a RegExp object, then this is used directly.
30793    *    If the expression evaluates to a string, then it will be converted to a RegExp
30794    *    after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to
30795    *    `new RegExp('^abc$')`.<br />
30796    *    **Note:** Avoid using the `g` flag on the RegExp, as it will cause each successive search to
30797    *    start at the index of the last search's match, thus not taking the whole input value into
30798    *    account.
30799    * @param {string=} ngChange Angular expression to be executed when input changes due to user
30800    *    interaction with the input element.
30801    * @param {boolean=} [ngTrim=true] If set to false Angular will not automatically trim the input.
30802    *    This parameter is ignored for input[type=password] controls, which will never trim the
30803    *    input.
30804    *
30805    * @example
30806       <example name="text-input-directive" module="textInputExample">
30807         <file name="index.html">
30808          <script>
30809            angular.module('textInputExample', [])
30810              .controller('ExampleController', ['$scope', function($scope) {
30811                $scope.example = {
30812                  text: 'guest',
30813                  word: /^\s*\w*\s*$/
30814                };
30815              }]);
30816          </script>
30817          <form name="myForm" ng-controller="ExampleController">
30818            <label>Single word:
30819              <input type="text" name="input" ng-model="example.text"
30820                     ng-pattern="example.word" required ng-trim="false">
30821            </label>
30822            <div role="alert">
30823              <span class="error" ng-show="myForm.input.$error.required">
30824                Required!</span>
30825              <span class="error" ng-show="myForm.input.$error.pattern">
30826                Single word only!</span>
30827            </div>
30828            <tt>text = {{example.text}}</tt><br/>
30829            <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
30830            <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
30831            <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
30832            <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
30833           </form>
30834         </file>
30835         <file name="protractor.js" type="protractor">
30836           var text = element(by.binding('example.text'));
30837           var valid = element(by.binding('myForm.input.$valid'));
30838           var input = element(by.model('example.text'));
30839
30840           it('should initialize to model', function() {
30841             expect(text.getText()).toContain('guest');
30842             expect(valid.getText()).toContain('true');
30843           });
30844
30845           it('should be invalid if empty', function() {
30846             input.clear();
30847             input.sendKeys('');
30848
30849             expect(text.getText()).toEqual('text =');
30850             expect(valid.getText()).toContain('false');
30851           });
30852
30853           it('should be invalid if multi word', function() {
30854             input.clear();
30855             input.sendKeys('hello world');
30856
30857             expect(valid.getText()).toContain('false');
30858           });
30859         </file>
30860       </example>
30861    */
30862   'text': textInputType,
30863
30864     /**
30865      * @ngdoc input
30866      * @name input[date]
30867      *
30868      * @description
30869      * Input with date validation and transformation. In browsers that do not yet support
30870      * the HTML5 date input, a text element will be used. In that case, text must be entered in a valid ISO-8601
30871      * date format (yyyy-MM-dd), for example: `2009-01-06`. Since many
30872      * modern browsers do not yet support this input type, it is important to provide cues to users on the
30873      * expected input format via a placeholder or label.
30874      *
30875      * The model must always be a Date object, otherwise Angular will throw an error.
30876      * Invalid `Date` objects (dates whose `getTime()` is `NaN`) will be rendered as an empty string.
30877      *
30878      * The timezone to be used to read/write the `Date` instance in the model can be defined using
30879      * {@link ng.directive:ngModelOptions ngModelOptions}. By default, this is the timezone of the browser.
30880      *
30881      * @param {string} ngModel Assignable angular expression to data-bind to.
30882      * @param {string=} name Property name of the form under which the control is published.
30883      * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`. This must be a
30884      *   valid ISO date string (yyyy-MM-dd). You can also use interpolation inside this attribute
30885      *   (e.g. `min="{{minDate | date:'yyyy-MM-dd'}}"`). Note that `min` will also add native HTML5
30886      *   constraint validation.
30887      * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`. This must be
30888      *   a valid ISO date string (yyyy-MM-dd). You can also use interpolation inside this attribute
30889      *   (e.g. `max="{{maxDate | date:'yyyy-MM-dd'}}"`). Note that `max` will also add native HTML5
30890      *   constraint validation.
30891      * @param {(date|string)=} ngMin Sets the `min` validation constraint to the Date / ISO date string
30892      *   the `ngMin` expression evaluates to. Note that it does not set the `min` attribute.
30893      * @param {(date|string)=} ngMax Sets the `max` validation constraint to the Date / ISO date string
30894      *   the `ngMax` expression evaluates to. Note that it does not set the `max` attribute.
30895      * @param {string=} required Sets `required` validation error key if the value is not entered.
30896      * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
30897      *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
30898      *    `required` when you want to data-bind to the `required` attribute.
30899      * @param {string=} ngChange Angular expression to be executed when input changes due to user
30900      *    interaction with the input element.
30901      *
30902      * @example
30903      <example name="date-input-directive" module="dateInputExample">
30904      <file name="index.html">
30905        <script>
30906           angular.module('dateInputExample', [])
30907             .controller('DateController', ['$scope', function($scope) {
30908               $scope.example = {
30909                 value: new Date(2013, 9, 22)
30910               };
30911             }]);
30912        </script>
30913        <form name="myForm" ng-controller="DateController as dateCtrl">
30914           <label for="exampleInput">Pick a date in 2013:</label>
30915           <input type="date" id="exampleInput" name="input" ng-model="example.value"
30916               placeholder="yyyy-MM-dd" min="2013-01-01" max="2013-12-31" required />
30917           <div role="alert">
30918             <span class="error" ng-show="myForm.input.$error.required">
30919                 Required!</span>
30920             <span class="error" ng-show="myForm.input.$error.date">
30921                 Not a valid date!</span>
30922            </div>
30923            <tt>value = {{example.value | date: "yyyy-MM-dd"}}</tt><br/>
30924            <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
30925            <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
30926            <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
30927            <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
30928        </form>
30929      </file>
30930      <file name="protractor.js" type="protractor">
30931         var value = element(by.binding('example.value | date: "yyyy-MM-dd"'));
30932         var valid = element(by.binding('myForm.input.$valid'));
30933         var input = element(by.model('example.value'));
30934
30935         // currently protractor/webdriver does not support
30936         // sending keys to all known HTML5 input controls
30937         // for various browsers (see https://github.com/angular/protractor/issues/562).
30938         function setInput(val) {
30939           // set the value of the element and force validation.
30940           var scr = "var ipt = document.getElementById('exampleInput'); " +
30941           "ipt.value = '" + val + "';" +
30942           "angular.element(ipt).scope().$apply(function(s) { s.myForm[ipt.name].$setViewValue('" + val + "'); });";
30943           browser.executeScript(scr);
30944         }
30945
30946         it('should initialize to model', function() {
30947           expect(value.getText()).toContain('2013-10-22');
30948           expect(valid.getText()).toContain('myForm.input.$valid = true');
30949         });
30950
30951         it('should be invalid if empty', function() {
30952           setInput('');
30953           expect(value.getText()).toEqual('value =');
30954           expect(valid.getText()).toContain('myForm.input.$valid = false');
30955         });
30956
30957         it('should be invalid if over max', function() {
30958           setInput('2015-01-01');
30959           expect(value.getText()).toContain('');
30960           expect(valid.getText()).toContain('myForm.input.$valid = false');
30961         });
30962      </file>
30963      </example>
30964      */
30965   'date': createDateInputType('date', DATE_REGEXP,
30966          createDateParser(DATE_REGEXP, ['yyyy', 'MM', 'dd']),
30967          'yyyy-MM-dd'),
30968
30969    /**
30970     * @ngdoc input
30971     * @name input[datetime-local]
30972     *
30973     * @description
30974     * Input with datetime validation and transformation. In browsers that do not yet support
30975     * the HTML5 date input, a text element will be used. In that case, the text must be entered in a valid ISO-8601
30976     * local datetime format (yyyy-MM-ddTHH:mm:ss), for example: `2010-12-28T14:57:00`.
30977     *
30978     * The model must always be a Date object, otherwise Angular will throw an error.
30979     * Invalid `Date` objects (dates whose `getTime()` is `NaN`) will be rendered as an empty string.
30980     *
30981     * The timezone to be used to read/write the `Date` instance in the model can be defined using
30982     * {@link ng.directive:ngModelOptions ngModelOptions}. By default, this is the timezone of the browser.
30983     *
30984     * @param {string} ngModel Assignable angular expression to data-bind to.
30985     * @param {string=} name Property name of the form under which the control is published.
30986     * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`.
30987     *   This must be a valid ISO datetime format (yyyy-MM-ddTHH:mm:ss). You can also use interpolation
30988     *   inside this attribute (e.g. `min="{{minDatetimeLocal | date:'yyyy-MM-ddTHH:mm:ss'}}"`).
30989     *   Note that `min` will also add native HTML5 constraint validation.
30990     * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`.
30991     *   This must be a valid ISO datetime format (yyyy-MM-ddTHH:mm:ss). You can also use interpolation
30992     *   inside this attribute (e.g. `max="{{maxDatetimeLocal | date:'yyyy-MM-ddTHH:mm:ss'}}"`).
30993     *   Note that `max` will also add native HTML5 constraint validation.
30994     * @param {(date|string)=} ngMin Sets the `min` validation error key to the Date / ISO datetime string
30995     *   the `ngMin` expression evaluates to. Note that it does not set the `min` attribute.
30996     * @param {(date|string)=} ngMax Sets the `max` validation error key to the Date / ISO datetime string
30997     *   the `ngMax` expression evaluates to. Note that it does not set the `max` attribute.
30998     * @param {string=} required Sets `required` validation error key if the value is not entered.
30999     * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
31000     *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
31001     *    `required` when you want to data-bind to the `required` attribute.
31002     * @param {string=} ngChange Angular expression to be executed when input changes due to user
31003     *    interaction with the input element.
31004     *
31005     * @example
31006     <example name="datetimelocal-input-directive" module="dateExample">
31007     <file name="index.html">
31008       <script>
31009         angular.module('dateExample', [])
31010           .controller('DateController', ['$scope', function($scope) {
31011             $scope.example = {
31012               value: new Date(2010, 11, 28, 14, 57)
31013             };
31014           }]);
31015       </script>
31016       <form name="myForm" ng-controller="DateController as dateCtrl">
31017         <label for="exampleInput">Pick a date between in 2013:</label>
31018         <input type="datetime-local" id="exampleInput" name="input" ng-model="example.value"
31019             placeholder="yyyy-MM-ddTHH:mm:ss" min="2001-01-01T00:00:00" max="2013-12-31T00:00:00" required />
31020         <div role="alert">
31021           <span class="error" ng-show="myForm.input.$error.required">
31022               Required!</span>
31023           <span class="error" ng-show="myForm.input.$error.datetimelocal">
31024               Not a valid date!</span>
31025         </div>
31026         <tt>value = {{example.value | date: "yyyy-MM-ddTHH:mm:ss"}}</tt><br/>
31027         <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
31028         <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
31029         <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
31030         <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
31031       </form>
31032     </file>
31033     <file name="protractor.js" type="protractor">
31034       var value = element(by.binding('example.value | date: "yyyy-MM-ddTHH:mm:ss"'));
31035       var valid = element(by.binding('myForm.input.$valid'));
31036       var input = element(by.model('example.value'));
31037
31038       // currently protractor/webdriver does not support
31039       // sending keys to all known HTML5 input controls
31040       // for various browsers (https://github.com/angular/protractor/issues/562).
31041       function setInput(val) {
31042         // set the value of the element and force validation.
31043         var scr = "var ipt = document.getElementById('exampleInput'); " +
31044         "ipt.value = '" + val + "';" +
31045         "angular.element(ipt).scope().$apply(function(s) { s.myForm[ipt.name].$setViewValue('" + val + "'); });";
31046         browser.executeScript(scr);
31047       }
31048
31049       it('should initialize to model', function() {
31050         expect(value.getText()).toContain('2010-12-28T14:57:00');
31051         expect(valid.getText()).toContain('myForm.input.$valid = true');
31052       });
31053
31054       it('should be invalid if empty', function() {
31055         setInput('');
31056         expect(value.getText()).toEqual('value =');
31057         expect(valid.getText()).toContain('myForm.input.$valid = false');
31058       });
31059
31060       it('should be invalid if over max', function() {
31061         setInput('2015-01-01T23:59:00');
31062         expect(value.getText()).toContain('');
31063         expect(valid.getText()).toContain('myForm.input.$valid = false');
31064       });
31065     </file>
31066     </example>
31067     */
31068   'datetime-local': createDateInputType('datetimelocal', DATETIMELOCAL_REGEXP,
31069       createDateParser(DATETIMELOCAL_REGEXP, ['yyyy', 'MM', 'dd', 'HH', 'mm', 'ss', 'sss']),
31070       'yyyy-MM-ddTHH:mm:ss.sss'),
31071
31072   /**
31073    * @ngdoc input
31074    * @name input[time]
31075    *
31076    * @description
31077    * Input with time validation and transformation. In browsers that do not yet support
31078    * the HTML5 time input, a text element will be used. In that case, the text must be entered in a valid ISO-8601
31079    * local time format (HH:mm:ss), for example: `14:57:00`. Model must be a Date object. This binding will always output a
31080    * Date object to the model of January 1, 1970, or local date `new Date(1970, 0, 1, HH, mm, ss)`.
31081    *
31082    * The model must always be a Date object, otherwise Angular will throw an error.
31083    * Invalid `Date` objects (dates whose `getTime()` is `NaN`) will be rendered as an empty string.
31084    *
31085    * The timezone to be used to read/write the `Date` instance in the model can be defined using
31086    * {@link ng.directive:ngModelOptions ngModelOptions}. By default, this is the timezone of the browser.
31087    *
31088    * @param {string} ngModel Assignable angular expression to data-bind to.
31089    * @param {string=} name Property name of the form under which the control is published.
31090    * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`.
31091    *   This must be a valid ISO time format (HH:mm:ss). You can also use interpolation inside this
31092    *   attribute (e.g. `min="{{minTime | date:'HH:mm:ss'}}"`). Note that `min` will also add
31093    *   native HTML5 constraint validation.
31094    * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`.
31095    *   This must be a valid ISO time format (HH:mm:ss). You can also use interpolation inside this
31096    *   attribute (e.g. `max="{{maxTime | date:'HH:mm:ss'}}"`). Note that `max` will also add
31097    *   native HTML5 constraint validation.
31098    * @param {(date|string)=} ngMin Sets the `min` validation constraint to the Date / ISO time string the
31099    *   `ngMin` expression evaluates to. Note that it does not set the `min` attribute.
31100    * @param {(date|string)=} ngMax Sets the `max` validation constraint to the Date / ISO time string the
31101    *   `ngMax` expression evaluates to. Note that it does not set the `max` attribute.
31102    * @param {string=} required Sets `required` validation error key if the value is not entered.
31103    * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
31104    *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
31105    *    `required` when you want to data-bind to the `required` attribute.
31106    * @param {string=} ngChange Angular expression to be executed when input changes due to user
31107    *    interaction with the input element.
31108    *
31109    * @example
31110    <example name="time-input-directive" module="timeExample">
31111    <file name="index.html">
31112      <script>
31113       angular.module('timeExample', [])
31114         .controller('DateController', ['$scope', function($scope) {
31115           $scope.example = {
31116             value: new Date(1970, 0, 1, 14, 57, 0)
31117           };
31118         }]);
31119      </script>
31120      <form name="myForm" ng-controller="DateController as dateCtrl">
31121         <label for="exampleInput">Pick a between 8am and 5pm:</label>
31122         <input type="time" id="exampleInput" name="input" ng-model="example.value"
31123             placeholder="HH:mm:ss" min="08:00:00" max="17:00:00" required />
31124         <div role="alert">
31125           <span class="error" ng-show="myForm.input.$error.required">
31126               Required!</span>
31127           <span class="error" ng-show="myForm.input.$error.time">
31128               Not a valid date!</span>
31129         </div>
31130         <tt>value = {{example.value | date: "HH:mm:ss"}}</tt><br/>
31131         <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
31132         <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
31133         <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
31134         <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
31135      </form>
31136    </file>
31137    <file name="protractor.js" type="protractor">
31138       var value = element(by.binding('example.value | date: "HH:mm:ss"'));
31139       var valid = element(by.binding('myForm.input.$valid'));
31140       var input = element(by.model('example.value'));
31141
31142       // currently protractor/webdriver does not support
31143       // sending keys to all known HTML5 input controls
31144       // for various browsers (https://github.com/angular/protractor/issues/562).
31145       function setInput(val) {
31146         // set the value of the element and force validation.
31147         var scr = "var ipt = document.getElementById('exampleInput'); " +
31148         "ipt.value = '" + val + "';" +
31149         "angular.element(ipt).scope().$apply(function(s) { s.myForm[ipt.name].$setViewValue('" + val + "'); });";
31150         browser.executeScript(scr);
31151       }
31152
31153       it('should initialize to model', function() {
31154         expect(value.getText()).toContain('14:57:00');
31155         expect(valid.getText()).toContain('myForm.input.$valid = true');
31156       });
31157
31158       it('should be invalid if empty', function() {
31159         setInput('');
31160         expect(value.getText()).toEqual('value =');
31161         expect(valid.getText()).toContain('myForm.input.$valid = false');
31162       });
31163
31164       it('should be invalid if over max', function() {
31165         setInput('23:59:00');
31166         expect(value.getText()).toContain('');
31167         expect(valid.getText()).toContain('myForm.input.$valid = false');
31168       });
31169    </file>
31170    </example>
31171    */
31172   'time': createDateInputType('time', TIME_REGEXP,
31173       createDateParser(TIME_REGEXP, ['HH', 'mm', 'ss', 'sss']),
31174      'HH:mm:ss.sss'),
31175
31176    /**
31177     * @ngdoc input
31178     * @name input[week]
31179     *
31180     * @description
31181     * Input with week-of-the-year validation and transformation to Date. In browsers that do not yet support
31182     * the HTML5 week input, a text element will be used. In that case, the text must be entered in a valid ISO-8601
31183     * week format (yyyy-W##), for example: `2013-W02`.
31184     *
31185     * The model must always be a Date object, otherwise Angular will throw an error.
31186     * Invalid `Date` objects (dates whose `getTime()` is `NaN`) will be rendered as an empty string.
31187     *
31188     * The timezone to be used to read/write the `Date` instance in the model can be defined using
31189     * {@link ng.directive:ngModelOptions ngModelOptions}. By default, this is the timezone of the browser.
31190     *
31191     * @param {string} ngModel Assignable angular expression to data-bind to.
31192     * @param {string=} name Property name of the form under which the control is published.
31193     * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`.
31194     *   This must be a valid ISO week format (yyyy-W##). You can also use interpolation inside this
31195     *   attribute (e.g. `min="{{minWeek | date:'yyyy-Www'}}"`). Note that `min` will also add
31196     *   native HTML5 constraint validation.
31197     * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`.
31198     *   This must be a valid ISO week format (yyyy-W##). You can also use interpolation inside this
31199     *   attribute (e.g. `max="{{maxWeek | date:'yyyy-Www'}}"`). Note that `max` will also add
31200     *   native HTML5 constraint validation.
31201     * @param {(date|string)=} ngMin Sets the `min` validation constraint to the Date / ISO week string
31202     *   the `ngMin` expression evaluates to. Note that it does not set the `min` attribute.
31203     * @param {(date|string)=} ngMax Sets the `max` validation constraint to the Date / ISO week string
31204     *   the `ngMax` expression evaluates to. Note that it does not set the `max` attribute.
31205     * @param {string=} required Sets `required` validation error key if the value is not entered.
31206     * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
31207     *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
31208     *    `required` when you want to data-bind to the `required` attribute.
31209     * @param {string=} ngChange Angular expression to be executed when input changes due to user
31210     *    interaction with the input element.
31211     *
31212     * @example
31213     <example name="week-input-directive" module="weekExample">
31214     <file name="index.html">
31215       <script>
31216       angular.module('weekExample', [])
31217         .controller('DateController', ['$scope', function($scope) {
31218           $scope.example = {
31219             value: new Date(2013, 0, 3)
31220           };
31221         }]);
31222       </script>
31223       <form name="myForm" ng-controller="DateController as dateCtrl">
31224         <label>Pick a date between in 2013:
31225           <input id="exampleInput" type="week" name="input" ng-model="example.value"
31226                  placeholder="YYYY-W##" min="2012-W32"
31227                  max="2013-W52" required />
31228         </label>
31229         <div role="alert">
31230           <span class="error" ng-show="myForm.input.$error.required">
31231               Required!</span>
31232           <span class="error" ng-show="myForm.input.$error.week">
31233               Not a valid date!</span>
31234         </div>
31235         <tt>value = {{example.value | date: "yyyy-Www"}}</tt><br/>
31236         <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
31237         <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
31238         <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
31239         <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
31240       </form>
31241     </file>
31242     <file name="protractor.js" type="protractor">
31243       var value = element(by.binding('example.value | date: "yyyy-Www"'));
31244       var valid = element(by.binding('myForm.input.$valid'));
31245       var input = element(by.model('example.value'));
31246
31247       // currently protractor/webdriver does not support
31248       // sending keys to all known HTML5 input controls
31249       // for various browsers (https://github.com/angular/protractor/issues/562).
31250       function setInput(val) {
31251         // set the value of the element and force validation.
31252         var scr = "var ipt = document.getElementById('exampleInput'); " +
31253         "ipt.value = '" + val + "';" +
31254         "angular.element(ipt).scope().$apply(function(s) { s.myForm[ipt.name].$setViewValue('" + val + "'); });";
31255         browser.executeScript(scr);
31256       }
31257
31258       it('should initialize to model', function() {
31259         expect(value.getText()).toContain('2013-W01');
31260         expect(valid.getText()).toContain('myForm.input.$valid = true');
31261       });
31262
31263       it('should be invalid if empty', function() {
31264         setInput('');
31265         expect(value.getText()).toEqual('value =');
31266         expect(valid.getText()).toContain('myForm.input.$valid = false');
31267       });
31268
31269       it('should be invalid if over max', function() {
31270         setInput('2015-W01');
31271         expect(value.getText()).toContain('');
31272         expect(valid.getText()).toContain('myForm.input.$valid = false');
31273       });
31274     </file>
31275     </example>
31276     */
31277   'week': createDateInputType('week', WEEK_REGEXP, weekParser, 'yyyy-Www'),
31278
31279   /**
31280    * @ngdoc input
31281    * @name input[month]
31282    *
31283    * @description
31284    * Input with month validation and transformation. In browsers that do not yet support
31285    * the HTML5 month input, a text element will be used. In that case, the text must be entered in a valid ISO-8601
31286    * month format (yyyy-MM), for example: `2009-01`.
31287    *
31288    * The model must always be a Date object, otherwise Angular will throw an error.
31289    * Invalid `Date` objects (dates whose `getTime()` is `NaN`) will be rendered as an empty string.
31290    * If the model is not set to the first of the month, the next view to model update will set it
31291    * to the first of the month.
31292    *
31293    * The timezone to be used to read/write the `Date` instance in the model can be defined using
31294    * {@link ng.directive:ngModelOptions ngModelOptions}. By default, this is the timezone of the browser.
31295    *
31296    * @param {string} ngModel Assignable angular expression to data-bind to.
31297    * @param {string=} name Property name of the form under which the control is published.
31298    * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`.
31299    *   This must be a valid ISO month format (yyyy-MM). You can also use interpolation inside this
31300    *   attribute (e.g. `min="{{minMonth | date:'yyyy-MM'}}"`). Note that `min` will also add
31301    *   native HTML5 constraint validation.
31302    * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`.
31303    *   This must be a valid ISO month format (yyyy-MM). You can also use interpolation inside this
31304    *   attribute (e.g. `max="{{maxMonth | date:'yyyy-MM'}}"`). Note that `max` will also add
31305    *   native HTML5 constraint validation.
31306    * @param {(date|string)=} ngMin Sets the `min` validation constraint to the Date / ISO week string
31307    *   the `ngMin` expression evaluates to. Note that it does not set the `min` attribute.
31308    * @param {(date|string)=} ngMax Sets the `max` validation constraint to the Date / ISO week string
31309    *   the `ngMax` expression evaluates to. Note that it does not set the `max` attribute.
31310
31311    * @param {string=} required Sets `required` validation error key if the value is not entered.
31312    * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
31313    *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
31314    *    `required` when you want to data-bind to the `required` attribute.
31315    * @param {string=} ngChange Angular expression to be executed when input changes due to user
31316    *    interaction with the input element.
31317    *
31318    * @example
31319    <example name="month-input-directive" module="monthExample">
31320    <file name="index.html">
31321      <script>
31322       angular.module('monthExample', [])
31323         .controller('DateController', ['$scope', function($scope) {
31324           $scope.example = {
31325             value: new Date(2013, 9, 1)
31326           };
31327         }]);
31328      </script>
31329      <form name="myForm" ng-controller="DateController as dateCtrl">
31330        <label for="exampleInput">Pick a month in 2013:</label>
31331        <input id="exampleInput" type="month" name="input" ng-model="example.value"
31332           placeholder="yyyy-MM" min="2013-01" max="2013-12" required />
31333        <div role="alert">
31334          <span class="error" ng-show="myForm.input.$error.required">
31335             Required!</span>
31336          <span class="error" ng-show="myForm.input.$error.month">
31337             Not a valid month!</span>
31338        </div>
31339        <tt>value = {{example.value | date: "yyyy-MM"}}</tt><br/>
31340        <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
31341        <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
31342        <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
31343        <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
31344      </form>
31345    </file>
31346    <file name="protractor.js" type="protractor">
31347       var value = element(by.binding('example.value | date: "yyyy-MM"'));
31348       var valid = element(by.binding('myForm.input.$valid'));
31349       var input = element(by.model('example.value'));
31350
31351       // currently protractor/webdriver does not support
31352       // sending keys to all known HTML5 input controls
31353       // for various browsers (https://github.com/angular/protractor/issues/562).
31354       function setInput(val) {
31355         // set the value of the element and force validation.
31356         var scr = "var ipt = document.getElementById('exampleInput'); " +
31357         "ipt.value = '" + val + "';" +
31358         "angular.element(ipt).scope().$apply(function(s) { s.myForm[ipt.name].$setViewValue('" + val + "'); });";
31359         browser.executeScript(scr);
31360       }
31361
31362       it('should initialize to model', function() {
31363         expect(value.getText()).toContain('2013-10');
31364         expect(valid.getText()).toContain('myForm.input.$valid = true');
31365       });
31366
31367       it('should be invalid if empty', function() {
31368         setInput('');
31369         expect(value.getText()).toEqual('value =');
31370         expect(valid.getText()).toContain('myForm.input.$valid = false');
31371       });
31372
31373       it('should be invalid if over max', function() {
31374         setInput('2015-01');
31375         expect(value.getText()).toContain('');
31376         expect(valid.getText()).toContain('myForm.input.$valid = false');
31377       });
31378    </file>
31379    </example>
31380    */
31381   'month': createDateInputType('month', MONTH_REGEXP,
31382      createDateParser(MONTH_REGEXP, ['yyyy', 'MM']),
31383      'yyyy-MM'),
31384
31385   /**
31386    * @ngdoc input
31387    * @name input[number]
31388    *
31389    * @description
31390    * Text input with number validation and transformation. Sets the `number` validation
31391    * error if not a valid number.
31392    *
31393    * <div class="alert alert-warning">
31394    * The model must always be of type `number` otherwise Angular will throw an error.
31395    * Be aware that a string containing a number is not enough. See the {@link ngModel:numfmt}
31396    * error docs for more information and an example of how to convert your model if necessary.
31397    * </div>
31398    *
31399    * ## Issues with HTML5 constraint validation
31400    *
31401    * In browsers that follow the
31402    * [HTML5 specification](https://html.spec.whatwg.org/multipage/forms.html#number-state-%28type=number%29),
31403    * `input[number]` does not work as expected with {@link ngModelOptions `ngModelOptions.allowInvalid`}.
31404    * If a non-number is entered in the input, the browser will report the value as an empty string,
31405    * which means the view / model values in `ngModel` and subsequently the scope value
31406    * will also be an empty string.
31407    *
31408    *
31409    * @param {string} ngModel Assignable angular expression to data-bind to.
31410    * @param {string=} name Property name of the form under which the control is published.
31411    * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`.
31412    * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`.
31413    * @param {string=} required Sets `required` validation error key if the value is not entered.
31414    * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
31415    *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
31416    *    `required` when you want to data-bind to the `required` attribute.
31417    * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
31418    *    minlength.
31419    * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
31420    *    maxlength. Setting the attribute to a negative or non-numeric value, allows view values of
31421    *    any length.
31422    * @param {string=} pattern Similar to `ngPattern` except that the attribute value is the actual string
31423    *    that contains the regular expression body that will be converted to a regular expression
31424    *    as in the ngPattern directive.
31425    * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel {@link ngModel.NgModelController#$viewValue $viewValue}
31426    *    does not match a RegExp found by evaluating the Angular expression given in the attribute value.
31427    *    If the expression evaluates to a RegExp object, then this is used directly.
31428    *    If the expression evaluates to a string, then it will be converted to a RegExp
31429    *    after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to
31430    *    `new RegExp('^abc$')`.<br />
31431    *    **Note:** Avoid using the `g` flag on the RegExp, as it will cause each successive search to
31432    *    start at the index of the last search's match, thus not taking the whole input value into
31433    *    account.
31434    * @param {string=} ngChange Angular expression to be executed when input changes due to user
31435    *    interaction with the input element.
31436    *
31437    * @example
31438       <example name="number-input-directive" module="numberExample">
31439         <file name="index.html">
31440          <script>
31441            angular.module('numberExample', [])
31442              .controller('ExampleController', ['$scope', function($scope) {
31443                $scope.example = {
31444                  value: 12
31445                };
31446              }]);
31447          </script>
31448          <form name="myForm" ng-controller="ExampleController">
31449            <label>Number:
31450              <input type="number" name="input" ng-model="example.value"
31451                     min="0" max="99" required>
31452           </label>
31453            <div role="alert">
31454              <span class="error" ng-show="myForm.input.$error.required">
31455                Required!</span>
31456              <span class="error" ng-show="myForm.input.$error.number">
31457                Not valid number!</span>
31458            </div>
31459            <tt>value = {{example.value}}</tt><br/>
31460            <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
31461            <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
31462            <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
31463            <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
31464           </form>
31465         </file>
31466         <file name="protractor.js" type="protractor">
31467           var value = element(by.binding('example.value'));
31468           var valid = element(by.binding('myForm.input.$valid'));
31469           var input = element(by.model('example.value'));
31470
31471           it('should initialize to model', function() {
31472             expect(value.getText()).toContain('12');
31473             expect(valid.getText()).toContain('true');
31474           });
31475
31476           it('should be invalid if empty', function() {
31477             input.clear();
31478             input.sendKeys('');
31479             expect(value.getText()).toEqual('value =');
31480             expect(valid.getText()).toContain('false');
31481           });
31482
31483           it('should be invalid if over max', function() {
31484             input.clear();
31485             input.sendKeys('123');
31486             expect(value.getText()).toEqual('value =');
31487             expect(valid.getText()).toContain('false');
31488           });
31489         </file>
31490       </example>
31491    */
31492   'number': numberInputType,
31493
31494
31495   /**
31496    * @ngdoc input
31497    * @name input[url]
31498    *
31499    * @description
31500    * Text input with URL validation. Sets the `url` validation error key if the content is not a
31501    * valid URL.
31502    *
31503    * <div class="alert alert-warning">
31504    * **Note:** `input[url]` uses a regex to validate urls that is derived from the regex
31505    * used in Chromium. If you need stricter validation, you can use `ng-pattern` or modify
31506    * the built-in validators (see the {@link guide/forms Forms guide})
31507    * </div>
31508    *
31509    * @param {string} ngModel Assignable angular expression to data-bind to.
31510    * @param {string=} name Property name of the form under which the control is published.
31511    * @param {string=} required Sets `required` validation error key if the value is not entered.
31512    * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
31513    *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
31514    *    `required` when you want to data-bind to the `required` attribute.
31515    * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
31516    *    minlength.
31517    * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
31518    *    maxlength. Setting the attribute to a negative or non-numeric value, allows view values of
31519    *    any length.
31520    * @param {string=} pattern Similar to `ngPattern` except that the attribute value is the actual string
31521    *    that contains the regular expression body that will be converted to a regular expression
31522    *    as in the ngPattern directive.
31523    * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel {@link ngModel.NgModelController#$viewValue $viewValue}
31524    *    does not match a RegExp found by evaluating the Angular expression given in the attribute value.
31525    *    If the expression evaluates to a RegExp object, then this is used directly.
31526    *    If the expression evaluates to a string, then it will be converted to a RegExp
31527    *    after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to
31528    *    `new RegExp('^abc$')`.<br />
31529    *    **Note:** Avoid using the `g` flag on the RegExp, as it will cause each successive search to
31530    *    start at the index of the last search's match, thus not taking the whole input value into
31531    *    account.
31532    * @param {string=} ngChange Angular expression to be executed when input changes due to user
31533    *    interaction with the input element.
31534    *
31535    * @example
31536       <example name="url-input-directive" module="urlExample">
31537         <file name="index.html">
31538          <script>
31539            angular.module('urlExample', [])
31540              .controller('ExampleController', ['$scope', function($scope) {
31541                $scope.url = {
31542                  text: 'http://google.com'
31543                };
31544              }]);
31545          </script>
31546          <form name="myForm" ng-controller="ExampleController">
31547            <label>URL:
31548              <input type="url" name="input" ng-model="url.text" required>
31549            <label>
31550            <div role="alert">
31551              <span class="error" ng-show="myForm.input.$error.required">
31552                Required!</span>
31553              <span class="error" ng-show="myForm.input.$error.url">
31554                Not valid url!</span>
31555            </div>
31556            <tt>text = {{url.text}}</tt><br/>
31557            <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
31558            <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
31559            <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
31560            <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
31561            <tt>myForm.$error.url = {{!!myForm.$error.url}}</tt><br/>
31562           </form>
31563         </file>
31564         <file name="protractor.js" type="protractor">
31565           var text = element(by.binding('url.text'));
31566           var valid = element(by.binding('myForm.input.$valid'));
31567           var input = element(by.model('url.text'));
31568
31569           it('should initialize to model', function() {
31570             expect(text.getText()).toContain('http://google.com');
31571             expect(valid.getText()).toContain('true');
31572           });
31573
31574           it('should be invalid if empty', function() {
31575             input.clear();
31576             input.sendKeys('');
31577
31578             expect(text.getText()).toEqual('text =');
31579             expect(valid.getText()).toContain('false');
31580           });
31581
31582           it('should be invalid if not url', function() {
31583             input.clear();
31584             input.sendKeys('box');
31585
31586             expect(valid.getText()).toContain('false');
31587           });
31588         </file>
31589       </example>
31590    */
31591   'url': urlInputType,
31592
31593
31594   /**
31595    * @ngdoc input
31596    * @name input[email]
31597    *
31598    * @description
31599    * Text input with email validation. Sets the `email` validation error key if not a valid email
31600    * address.
31601    *
31602    * <div class="alert alert-warning">
31603    * **Note:** `input[email]` uses a regex to validate email addresses that is derived from the regex
31604    * used in Chromium. If you need stricter validation (e.g. requiring a top-level domain), you can
31605    * use `ng-pattern` or modify the built-in validators (see the {@link guide/forms Forms guide})
31606    * </div>
31607    *
31608    * @param {string} ngModel Assignable angular expression to data-bind to.
31609    * @param {string=} name Property name of the form under which the control is published.
31610    * @param {string=} required Sets `required` validation error key if the value is not entered.
31611    * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
31612    *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
31613    *    `required` when you want to data-bind to the `required` attribute.
31614    * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
31615    *    minlength.
31616    * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
31617    *    maxlength. Setting the attribute to a negative or non-numeric value, allows view values of
31618    *    any length.
31619    * @param {string=} pattern Similar to `ngPattern` except that the attribute value is the actual string
31620    *    that contains the regular expression body that will be converted to a regular expression
31621    *    as in the ngPattern directive.
31622    * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel {@link ngModel.NgModelController#$viewValue $viewValue}
31623    *    does not match a RegExp found by evaluating the Angular expression given in the attribute value.
31624    *    If the expression evaluates to a RegExp object, then this is used directly.
31625    *    If the expression evaluates to a string, then it will be converted to a RegExp
31626    *    after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to
31627    *    `new RegExp('^abc$')`.<br />
31628    *    **Note:** Avoid using the `g` flag on the RegExp, as it will cause each successive search to
31629    *    start at the index of the last search's match, thus not taking the whole input value into
31630    *    account.
31631    * @param {string=} ngChange Angular expression to be executed when input changes due to user
31632    *    interaction with the input element.
31633    *
31634    * @example
31635       <example name="email-input-directive" module="emailExample">
31636         <file name="index.html">
31637          <script>
31638            angular.module('emailExample', [])
31639              .controller('ExampleController', ['$scope', function($scope) {
31640                $scope.email = {
31641                  text: 'me@example.com'
31642                };
31643              }]);
31644          </script>
31645            <form name="myForm" ng-controller="ExampleController">
31646              <label>Email:
31647                <input type="email" name="input" ng-model="email.text" required>
31648              </label>
31649              <div role="alert">
31650                <span class="error" ng-show="myForm.input.$error.required">
31651                  Required!</span>
31652                <span class="error" ng-show="myForm.input.$error.email">
31653                  Not valid email!</span>
31654              </div>
31655              <tt>text = {{email.text}}</tt><br/>
31656              <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
31657              <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
31658              <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
31659              <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
31660              <tt>myForm.$error.email = {{!!myForm.$error.email}}</tt><br/>
31661            </form>
31662          </file>
31663         <file name="protractor.js" type="protractor">
31664           var text = element(by.binding('email.text'));
31665           var valid = element(by.binding('myForm.input.$valid'));
31666           var input = element(by.model('email.text'));
31667
31668           it('should initialize to model', function() {
31669             expect(text.getText()).toContain('me@example.com');
31670             expect(valid.getText()).toContain('true');
31671           });
31672
31673           it('should be invalid if empty', function() {
31674             input.clear();
31675             input.sendKeys('');
31676             expect(text.getText()).toEqual('text =');
31677             expect(valid.getText()).toContain('false');
31678           });
31679
31680           it('should be invalid if not email', function() {
31681             input.clear();
31682             input.sendKeys('xxx');
31683
31684             expect(valid.getText()).toContain('false');
31685           });
31686         </file>
31687       </example>
31688    */
31689   'email': emailInputType,
31690
31691
31692   /**
31693    * @ngdoc input
31694    * @name input[radio]
31695    *
31696    * @description
31697    * HTML radio button.
31698    *
31699    * @param {string} ngModel Assignable angular expression to data-bind to.
31700    * @param {string} value The value to which the `ngModel` expression should be set when selected.
31701    *    Note that `value` only supports `string` values, i.e. the scope model needs to be a string,
31702    *    too. Use `ngValue` if you need complex models (`number`, `object`, ...).
31703    * @param {string=} name Property name of the form under which the control is published.
31704    * @param {string=} ngChange Angular expression to be executed when input changes due to user
31705    *    interaction with the input element.
31706    * @param {string} ngValue Angular expression to which `ngModel` will be be set when the radio
31707    *    is selected. Should be used instead of the `value` attribute if you need
31708    *    a non-string `ngModel` (`boolean`, `array`, ...).
31709    *
31710    * @example
31711       <example name="radio-input-directive" module="radioExample">
31712         <file name="index.html">
31713          <script>
31714            angular.module('radioExample', [])
31715              .controller('ExampleController', ['$scope', function($scope) {
31716                $scope.color = {
31717                  name: 'blue'
31718                };
31719                $scope.specialValue = {
31720                  "id": "12345",
31721                  "value": "green"
31722                };
31723              }]);
31724          </script>
31725          <form name="myForm" ng-controller="ExampleController">
31726            <label>
31727              <input type="radio" ng-model="color.name" value="red">
31728              Red
31729            </label><br/>
31730            <label>
31731              <input type="radio" ng-model="color.name" ng-value="specialValue">
31732              Green
31733            </label><br/>
31734            <label>
31735              <input type="radio" ng-model="color.name" value="blue">
31736              Blue
31737            </label><br/>
31738            <tt>color = {{color.name | json}}</tt><br/>
31739           </form>
31740           Note that `ng-value="specialValue"` sets radio item's value to be the value of `$scope.specialValue`.
31741         </file>
31742         <file name="protractor.js" type="protractor">
31743           it('should change state', function() {
31744             var color = element(by.binding('color.name'));
31745
31746             expect(color.getText()).toContain('blue');
31747
31748             element.all(by.model('color.name')).get(0).click();
31749
31750             expect(color.getText()).toContain('red');
31751           });
31752         </file>
31753       </example>
31754    */
31755   'radio': radioInputType,
31756
31757
31758   /**
31759    * @ngdoc input
31760    * @name input[checkbox]
31761    *
31762    * @description
31763    * HTML checkbox.
31764    *
31765    * @param {string} ngModel Assignable angular expression to data-bind to.
31766    * @param {string=} name Property name of the form under which the control is published.
31767    * @param {expression=} ngTrueValue The value to which the expression should be set when selected.
31768    * @param {expression=} ngFalseValue The value to which the expression should be set when not selected.
31769    * @param {string=} ngChange Angular expression to be executed when input changes due to user
31770    *    interaction with the input element.
31771    *
31772    * @example
31773       <example name="checkbox-input-directive" module="checkboxExample">
31774         <file name="index.html">
31775          <script>
31776            angular.module('checkboxExample', [])
31777              .controller('ExampleController', ['$scope', function($scope) {
31778                $scope.checkboxModel = {
31779                 value1 : true,
31780                 value2 : 'YES'
31781               };
31782              }]);
31783          </script>
31784          <form name="myForm" ng-controller="ExampleController">
31785            <label>Value1:
31786              <input type="checkbox" ng-model="checkboxModel.value1">
31787            </label><br/>
31788            <label>Value2:
31789              <input type="checkbox" ng-model="checkboxModel.value2"
31790                     ng-true-value="'YES'" ng-false-value="'NO'">
31791             </label><br/>
31792            <tt>value1 = {{checkboxModel.value1}}</tt><br/>
31793            <tt>value2 = {{checkboxModel.value2}}</tt><br/>
31794           </form>
31795         </file>
31796         <file name="protractor.js" type="protractor">
31797           it('should change state', function() {
31798             var value1 = element(by.binding('checkboxModel.value1'));
31799             var value2 = element(by.binding('checkboxModel.value2'));
31800
31801             expect(value1.getText()).toContain('true');
31802             expect(value2.getText()).toContain('YES');
31803
31804             element(by.model('checkboxModel.value1')).click();
31805             element(by.model('checkboxModel.value2')).click();
31806
31807             expect(value1.getText()).toContain('false');
31808             expect(value2.getText()).toContain('NO');
31809           });
31810         </file>
31811       </example>
31812    */
31813   'checkbox': checkboxInputType,
31814
31815   'hidden': noop,
31816   'button': noop,
31817   'submit': noop,
31818   'reset': noop,
31819   'file': noop
31820 };
31821
31822 function stringBasedInputType(ctrl) {
31823   ctrl.$formatters.push(function(value) {
31824     return ctrl.$isEmpty(value) ? value : value.toString();
31825   });
31826 }
31827
31828 function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {
31829   baseInputType(scope, element, attr, ctrl, $sniffer, $browser);
31830   stringBasedInputType(ctrl);
31831 }
31832
31833 function baseInputType(scope, element, attr, ctrl, $sniffer, $browser) {
31834   var type = lowercase(element[0].type);
31835
31836   // In composition mode, users are still inputing intermediate text buffer,
31837   // hold the listener until composition is done.
31838   // More about composition events: https://developer.mozilla.org/en-US/docs/Web/API/CompositionEvent
31839   if (!$sniffer.android) {
31840     var composing = false;
31841
31842     element.on('compositionstart', function(data) {
31843       composing = true;
31844     });
31845
31846     element.on('compositionend', function() {
31847       composing = false;
31848       listener();
31849     });
31850   }
31851
31852   var listener = function(ev) {
31853     if (timeout) {
31854       $browser.defer.cancel(timeout);
31855       timeout = null;
31856     }
31857     if (composing) return;
31858     var value = element.val(),
31859         event = ev && ev.type;
31860
31861     // By default we will trim the value
31862     // If the attribute ng-trim exists we will avoid trimming
31863     // If input type is 'password', the value is never trimmed
31864     if (type !== 'password' && (!attr.ngTrim || attr.ngTrim !== 'false')) {
31865       value = trim(value);
31866     }
31867
31868     // If a control is suffering from bad input (due to native validators), browsers discard its
31869     // value, so it may be necessary to revalidate (by calling $setViewValue again) even if the
31870     // control's value is the same empty value twice in a row.
31871     if (ctrl.$viewValue !== value || (value === '' && ctrl.$$hasNativeValidators)) {
31872       ctrl.$setViewValue(value, event);
31873     }
31874   };
31875
31876   // if the browser does support "input" event, we are fine - except on IE9 which doesn't fire the
31877   // input event on backspace, delete or cut
31878   if ($sniffer.hasEvent('input')) {
31879     element.on('input', listener);
31880   } else {
31881     var timeout;
31882
31883     var deferListener = function(ev, input, origValue) {
31884       if (!timeout) {
31885         timeout = $browser.defer(function() {
31886           timeout = null;
31887           if (!input || input.value !== origValue) {
31888             listener(ev);
31889           }
31890         });
31891       }
31892     };
31893
31894     element.on('keydown', function(event) {
31895       var key = event.keyCode;
31896
31897       // ignore
31898       //    command            modifiers                   arrows
31899       if (key === 91 || (15 < key && key < 19) || (37 <= key && key <= 40)) return;
31900
31901       deferListener(event, this, this.value);
31902     });
31903
31904     // if user modifies input value using context menu in IE, we need "paste" and "cut" events to catch it
31905     if ($sniffer.hasEvent('paste')) {
31906       element.on('paste cut', deferListener);
31907     }
31908   }
31909
31910   // if user paste into input using mouse on older browser
31911   // or form autocomplete on newer browser, we need "change" event to catch it
31912   element.on('change', listener);
31913
31914   ctrl.$render = function() {
31915     // Workaround for Firefox validation #12102.
31916     var value = ctrl.$isEmpty(ctrl.$viewValue) ? '' : ctrl.$viewValue;
31917     if (element.val() !== value) {
31918       element.val(value);
31919     }
31920   };
31921 }
31922
31923 function weekParser(isoWeek, existingDate) {
31924   if (isDate(isoWeek)) {
31925     return isoWeek;
31926   }
31927
31928   if (isString(isoWeek)) {
31929     WEEK_REGEXP.lastIndex = 0;
31930     var parts = WEEK_REGEXP.exec(isoWeek);
31931     if (parts) {
31932       var year = +parts[1],
31933           week = +parts[2],
31934           hours = 0,
31935           minutes = 0,
31936           seconds = 0,
31937           milliseconds = 0,
31938           firstThurs = getFirstThursdayOfYear(year),
31939           addDays = (week - 1) * 7;
31940
31941       if (existingDate) {
31942         hours = existingDate.getHours();
31943         minutes = existingDate.getMinutes();
31944         seconds = existingDate.getSeconds();
31945         milliseconds = existingDate.getMilliseconds();
31946       }
31947
31948       return new Date(year, 0, firstThurs.getDate() + addDays, hours, minutes, seconds, milliseconds);
31949     }
31950   }
31951
31952   return NaN;
31953 }
31954
31955 function createDateParser(regexp, mapping) {
31956   return function(iso, date) {
31957     var parts, map;
31958
31959     if (isDate(iso)) {
31960       return iso;
31961     }
31962
31963     if (isString(iso)) {
31964       // When a date is JSON'ified to wraps itself inside of an extra
31965       // set of double quotes. This makes the date parsing code unable
31966       // to match the date string and parse it as a date.
31967       if (iso.charAt(0) == '"' && iso.charAt(iso.length - 1) == '"') {
31968         iso = iso.substring(1, iso.length - 1);
31969       }
31970       if (ISO_DATE_REGEXP.test(iso)) {
31971         return new Date(iso);
31972       }
31973       regexp.lastIndex = 0;
31974       parts = regexp.exec(iso);
31975
31976       if (parts) {
31977         parts.shift();
31978         if (date) {
31979           map = {
31980             yyyy: date.getFullYear(),
31981             MM: date.getMonth() + 1,
31982             dd: date.getDate(),
31983             HH: date.getHours(),
31984             mm: date.getMinutes(),
31985             ss: date.getSeconds(),
31986             sss: date.getMilliseconds() / 1000
31987           };
31988         } else {
31989           map = { yyyy: 1970, MM: 1, dd: 1, HH: 0, mm: 0, ss: 0, sss: 0 };
31990         }
31991
31992         forEach(parts, function(part, index) {
31993           if (index < mapping.length) {
31994             map[mapping[index]] = +part;
31995           }
31996         });
31997         return new Date(map.yyyy, map.MM - 1, map.dd, map.HH, map.mm, map.ss || 0, map.sss * 1000 || 0);
31998       }
31999     }
32000
32001     return NaN;
32002   };
32003 }
32004
32005 function createDateInputType(type, regexp, parseDate, format) {
32006   return function dynamicDateInputType(scope, element, attr, ctrl, $sniffer, $browser, $filter) {
32007     badInputChecker(scope, element, attr, ctrl);
32008     baseInputType(scope, element, attr, ctrl, $sniffer, $browser);
32009     var timezone = ctrl && ctrl.$options && ctrl.$options.timezone;
32010     var previousDate;
32011
32012     ctrl.$$parserName = type;
32013     ctrl.$parsers.push(function(value) {
32014       if (ctrl.$isEmpty(value)) return null;
32015       if (regexp.test(value)) {
32016         // Note: We cannot read ctrl.$modelValue, as there might be a different
32017         // parser/formatter in the processing chain so that the model
32018         // contains some different data format!
32019         var parsedDate = parseDate(value, previousDate);
32020         if (timezone) {
32021           parsedDate = convertTimezoneToLocal(parsedDate, timezone);
32022         }
32023         return parsedDate;
32024       }
32025       return undefined;
32026     });
32027
32028     ctrl.$formatters.push(function(value) {
32029       if (value && !isDate(value)) {
32030         throw ngModelMinErr('datefmt', 'Expected `{0}` to be a date', value);
32031       }
32032       if (isValidDate(value)) {
32033         previousDate = value;
32034         if (previousDate && timezone) {
32035           previousDate = convertTimezoneToLocal(previousDate, timezone, true);
32036         }
32037         return $filter('date')(value, format, timezone);
32038       } else {
32039         previousDate = null;
32040         return '';
32041       }
32042     });
32043
32044     if (isDefined(attr.min) || attr.ngMin) {
32045       var minVal;
32046       ctrl.$validators.min = function(value) {
32047         return !isValidDate(value) || isUndefined(minVal) || parseDate(value) >= minVal;
32048       };
32049       attr.$observe('min', function(val) {
32050         minVal = parseObservedDateValue(val);
32051         ctrl.$validate();
32052       });
32053     }
32054
32055     if (isDefined(attr.max) || attr.ngMax) {
32056       var maxVal;
32057       ctrl.$validators.max = function(value) {
32058         return !isValidDate(value) || isUndefined(maxVal) || parseDate(value) <= maxVal;
32059       };
32060       attr.$observe('max', function(val) {
32061         maxVal = parseObservedDateValue(val);
32062         ctrl.$validate();
32063       });
32064     }
32065
32066     function isValidDate(value) {
32067       // Invalid Date: getTime() returns NaN
32068       return value && !(value.getTime && value.getTime() !== value.getTime());
32069     }
32070
32071     function parseObservedDateValue(val) {
32072       return isDefined(val) && !isDate(val) ? parseDate(val) || undefined : val;
32073     }
32074   };
32075 }
32076
32077 function badInputChecker(scope, element, attr, ctrl) {
32078   var node = element[0];
32079   var nativeValidation = ctrl.$$hasNativeValidators = isObject(node.validity);
32080   if (nativeValidation) {
32081     ctrl.$parsers.push(function(value) {
32082       var validity = element.prop(VALIDITY_STATE_PROPERTY) || {};
32083       return validity.badInput || validity.typeMismatch ? undefined : value;
32084     });
32085   }
32086 }
32087
32088 function numberInputType(scope, element, attr, ctrl, $sniffer, $browser) {
32089   badInputChecker(scope, element, attr, ctrl);
32090   baseInputType(scope, element, attr, ctrl, $sniffer, $browser);
32091
32092   ctrl.$$parserName = 'number';
32093   ctrl.$parsers.push(function(value) {
32094     if (ctrl.$isEmpty(value))      return null;
32095     if (NUMBER_REGEXP.test(value)) return parseFloat(value);
32096     return undefined;
32097   });
32098
32099   ctrl.$formatters.push(function(value) {
32100     if (!ctrl.$isEmpty(value)) {
32101       if (!isNumber(value)) {
32102         throw ngModelMinErr('numfmt', 'Expected `{0}` to be a number', value);
32103       }
32104       value = value.toString();
32105     }
32106     return value;
32107   });
32108
32109   if (isDefined(attr.min) || attr.ngMin) {
32110     var minVal;
32111     ctrl.$validators.min = function(value) {
32112       return ctrl.$isEmpty(value) || isUndefined(minVal) || value >= minVal;
32113     };
32114
32115     attr.$observe('min', function(val) {
32116       if (isDefined(val) && !isNumber(val)) {
32117         val = parseFloat(val, 10);
32118       }
32119       minVal = isNumber(val) && !isNaN(val) ? val : undefined;
32120       // TODO(matsko): implement validateLater to reduce number of validations
32121       ctrl.$validate();
32122     });
32123   }
32124
32125   if (isDefined(attr.max) || attr.ngMax) {
32126     var maxVal;
32127     ctrl.$validators.max = function(value) {
32128       return ctrl.$isEmpty(value) || isUndefined(maxVal) || value <= maxVal;
32129     };
32130
32131     attr.$observe('max', function(val) {
32132       if (isDefined(val) && !isNumber(val)) {
32133         val = parseFloat(val, 10);
32134       }
32135       maxVal = isNumber(val) && !isNaN(val) ? val : undefined;
32136       // TODO(matsko): implement validateLater to reduce number of validations
32137       ctrl.$validate();
32138     });
32139   }
32140 }
32141
32142 function urlInputType(scope, element, attr, ctrl, $sniffer, $browser) {
32143   // Note: no badInputChecker here by purpose as `url` is only a validation
32144   // in browsers, i.e. we can always read out input.value even if it is not valid!
32145   baseInputType(scope, element, attr, ctrl, $sniffer, $browser);
32146   stringBasedInputType(ctrl);
32147
32148   ctrl.$$parserName = 'url';
32149   ctrl.$validators.url = function(modelValue, viewValue) {
32150     var value = modelValue || viewValue;
32151     return ctrl.$isEmpty(value) || URL_REGEXP.test(value);
32152   };
32153 }
32154
32155 function emailInputType(scope, element, attr, ctrl, $sniffer, $browser) {
32156   // Note: no badInputChecker here by purpose as `url` is only a validation
32157   // in browsers, i.e. we can always read out input.value even if it is not valid!
32158   baseInputType(scope, element, attr, ctrl, $sniffer, $browser);
32159   stringBasedInputType(ctrl);
32160
32161   ctrl.$$parserName = 'email';
32162   ctrl.$validators.email = function(modelValue, viewValue) {
32163     var value = modelValue || viewValue;
32164     return ctrl.$isEmpty(value) || EMAIL_REGEXP.test(value);
32165   };
32166 }
32167
32168 function radioInputType(scope, element, attr, ctrl) {
32169   // make the name unique, if not defined
32170   if (isUndefined(attr.name)) {
32171     element.attr('name', nextUid());
32172   }
32173
32174   var listener = function(ev) {
32175     if (element[0].checked) {
32176       ctrl.$setViewValue(attr.value, ev && ev.type);
32177     }
32178   };
32179
32180   element.on('click', listener);
32181
32182   ctrl.$render = function() {
32183     var value = attr.value;
32184     element[0].checked = (value == ctrl.$viewValue);
32185   };
32186
32187   attr.$observe('value', ctrl.$render);
32188 }
32189
32190 function parseConstantExpr($parse, context, name, expression, fallback) {
32191   var parseFn;
32192   if (isDefined(expression)) {
32193     parseFn = $parse(expression);
32194     if (!parseFn.constant) {
32195       throw ngModelMinErr('constexpr', 'Expected constant expression for `{0}`, but saw ' +
32196                                    '`{1}`.', name, expression);
32197     }
32198     return parseFn(context);
32199   }
32200   return fallback;
32201 }
32202
32203 function checkboxInputType(scope, element, attr, ctrl, $sniffer, $browser, $filter, $parse) {
32204   var trueValue = parseConstantExpr($parse, scope, 'ngTrueValue', attr.ngTrueValue, true);
32205   var falseValue = parseConstantExpr($parse, scope, 'ngFalseValue', attr.ngFalseValue, false);
32206
32207   var listener = function(ev) {
32208     ctrl.$setViewValue(element[0].checked, ev && ev.type);
32209   };
32210
32211   element.on('click', listener);
32212
32213   ctrl.$render = function() {
32214     element[0].checked = ctrl.$viewValue;
32215   };
32216
32217   // Override the standard `$isEmpty` because the $viewValue of an empty checkbox is always set to `false`
32218   // This is because of the parser below, which compares the `$modelValue` with `trueValue` to convert
32219   // it to a boolean.
32220   ctrl.$isEmpty = function(value) {
32221     return value === false;
32222   };
32223
32224   ctrl.$formatters.push(function(value) {
32225     return equals(value, trueValue);
32226   });
32227
32228   ctrl.$parsers.push(function(value) {
32229     return value ? trueValue : falseValue;
32230   });
32231 }
32232
32233
32234 /**
32235  * @ngdoc directive
32236  * @name textarea
32237  * @restrict E
32238  *
32239  * @description
32240  * HTML textarea element control with angular data-binding. The data-binding and validation
32241  * properties of this element are exactly the same as those of the
32242  * {@link ng.directive:input input element}.
32243  *
32244  * @param {string} ngModel Assignable angular expression to data-bind to.
32245  * @param {string=} name Property name of the form under which the control is published.
32246  * @param {string=} required Sets `required` validation error key if the value is not entered.
32247  * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
32248  *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
32249  *    `required` when you want to data-bind to the `required` attribute.
32250  * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
32251  *    minlength.
32252  * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
32253  *    maxlength. Setting the attribute to a negative or non-numeric value, allows view values of any
32254  *    length.
32255  * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel {@link ngModel.NgModelController#$viewValue $viewValue}
32256  *    does not match a RegExp found by evaluating the Angular expression given in the attribute value.
32257  *    If the expression evaluates to a RegExp object, then this is used directly.
32258  *    If the expression evaluates to a string, then it will be converted to a RegExp
32259  *    after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to
32260  *    `new RegExp('^abc$')`.<br />
32261  *    **Note:** Avoid using the `g` flag on the RegExp, as it will cause each successive search to
32262  *    start at the index of the last search's match, thus not taking the whole input value into
32263  *    account.
32264  * @param {string=} ngChange Angular expression to be executed when input changes due to user
32265  *    interaction with the input element.
32266  * @param {boolean=} [ngTrim=true] If set to false Angular will not automatically trim the input.
32267  */
32268
32269
32270 /**
32271  * @ngdoc directive
32272  * @name input
32273  * @restrict E
32274  *
32275  * @description
32276  * HTML input element control. When used together with {@link ngModel `ngModel`}, it provides data-binding,
32277  * input state control, and validation.
32278  * Input control follows HTML5 input types and polyfills the HTML5 validation behavior for older browsers.
32279  *
32280  * <div class="alert alert-warning">
32281  * **Note:** Not every feature offered is available for all input types.
32282  * Specifically, data binding and event handling via `ng-model` is unsupported for `input[file]`.
32283  * </div>
32284  *
32285  * @param {string} ngModel Assignable angular expression to data-bind to.
32286  * @param {string=} name Property name of the form under which the control is published.
32287  * @param {string=} required Sets `required` validation error key if the value is not entered.
32288  * @param {boolean=} ngRequired Sets `required` attribute if set to true
32289  * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
32290  *    minlength.
32291  * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
32292  *    maxlength. Setting the attribute to a negative or non-numeric value, allows view values of any
32293  *    length.
32294  * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel {@link ngModel.NgModelController#$viewValue $viewValue}
32295  *    value does not match a RegExp found by evaluating the Angular expression given in the attribute value.
32296  *    If the expression evaluates to a RegExp object, then this is used directly.
32297  *    If the expression evaluates to a string, then it will be converted to a RegExp
32298  *    after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to
32299  *    `new RegExp('^abc$')`.<br />
32300  *    **Note:** Avoid using the `g` flag on the RegExp, as it will cause each successive search to
32301  *    start at the index of the last search's match, thus not taking the whole input value into
32302  *    account.
32303  * @param {string=} ngChange Angular expression to be executed when input changes due to user
32304  *    interaction with the input element.
32305  * @param {boolean=} [ngTrim=true] If set to false Angular will not automatically trim the input.
32306  *    This parameter is ignored for input[type=password] controls, which will never trim the
32307  *    input.
32308  *
32309  * @example
32310     <example name="input-directive" module="inputExample">
32311       <file name="index.html">
32312        <script>
32313           angular.module('inputExample', [])
32314             .controller('ExampleController', ['$scope', function($scope) {
32315               $scope.user = {name: 'guest', last: 'visitor'};
32316             }]);
32317        </script>
32318        <div ng-controller="ExampleController">
32319          <form name="myForm">
32320            <label>
32321               User name:
32322               <input type="text" name="userName" ng-model="user.name" required>
32323            </label>
32324            <div role="alert">
32325              <span class="error" ng-show="myForm.userName.$error.required">
32326               Required!</span>
32327            </div>
32328            <label>
32329               Last name:
32330               <input type="text" name="lastName" ng-model="user.last"
32331               ng-minlength="3" ng-maxlength="10">
32332            </label>
32333            <div role="alert">
32334              <span class="error" ng-show="myForm.lastName.$error.minlength">
32335                Too short!</span>
32336              <span class="error" ng-show="myForm.lastName.$error.maxlength">
32337                Too long!</span>
32338            </div>
32339          </form>
32340          <hr>
32341          <tt>user = {{user}}</tt><br/>
32342          <tt>myForm.userName.$valid = {{myForm.userName.$valid}}</tt><br/>
32343          <tt>myForm.userName.$error = {{myForm.userName.$error}}</tt><br/>
32344          <tt>myForm.lastName.$valid = {{myForm.lastName.$valid}}</tt><br/>
32345          <tt>myForm.lastName.$error = {{myForm.lastName.$error}}</tt><br/>
32346          <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
32347          <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
32348          <tt>myForm.$error.minlength = {{!!myForm.$error.minlength}}</tt><br/>
32349          <tt>myForm.$error.maxlength = {{!!myForm.$error.maxlength}}</tt><br/>
32350        </div>
32351       </file>
32352       <file name="protractor.js" type="protractor">
32353         var user = element(by.exactBinding('user'));
32354         var userNameValid = element(by.binding('myForm.userName.$valid'));
32355         var lastNameValid = element(by.binding('myForm.lastName.$valid'));
32356         var lastNameError = element(by.binding('myForm.lastName.$error'));
32357         var formValid = element(by.binding('myForm.$valid'));
32358         var userNameInput = element(by.model('user.name'));
32359         var userLastInput = element(by.model('user.last'));
32360
32361         it('should initialize to model', function() {
32362           expect(user.getText()).toContain('{"name":"guest","last":"visitor"}');
32363           expect(userNameValid.getText()).toContain('true');
32364           expect(formValid.getText()).toContain('true');
32365         });
32366
32367         it('should be invalid if empty when required', function() {
32368           userNameInput.clear();
32369           userNameInput.sendKeys('');
32370
32371           expect(user.getText()).toContain('{"last":"visitor"}');
32372           expect(userNameValid.getText()).toContain('false');
32373           expect(formValid.getText()).toContain('false');
32374         });
32375
32376         it('should be valid if empty when min length is set', function() {
32377           userLastInput.clear();
32378           userLastInput.sendKeys('');
32379
32380           expect(user.getText()).toContain('{"name":"guest","last":""}');
32381           expect(lastNameValid.getText()).toContain('true');
32382           expect(formValid.getText()).toContain('true');
32383         });
32384
32385         it('should be invalid if less than required min length', function() {
32386           userLastInput.clear();
32387           userLastInput.sendKeys('xx');
32388
32389           expect(user.getText()).toContain('{"name":"guest"}');
32390           expect(lastNameValid.getText()).toContain('false');
32391           expect(lastNameError.getText()).toContain('minlength');
32392           expect(formValid.getText()).toContain('false');
32393         });
32394
32395         it('should be invalid if longer than max length', function() {
32396           userLastInput.clear();
32397           userLastInput.sendKeys('some ridiculously long name');
32398
32399           expect(user.getText()).toContain('{"name":"guest"}');
32400           expect(lastNameValid.getText()).toContain('false');
32401           expect(lastNameError.getText()).toContain('maxlength');
32402           expect(formValid.getText()).toContain('false');
32403         });
32404       </file>
32405     </example>
32406  */
32407 var inputDirective = ['$browser', '$sniffer', '$filter', '$parse',
32408     function($browser, $sniffer, $filter, $parse) {
32409   return {
32410     restrict: 'E',
32411     require: ['?ngModel'],
32412     link: {
32413       pre: function(scope, element, attr, ctrls) {
32414         if (ctrls[0]) {
32415           (inputType[lowercase(attr.type)] || inputType.text)(scope, element, attr, ctrls[0], $sniffer,
32416                                                               $browser, $filter, $parse);
32417         }
32418       }
32419     }
32420   };
32421 }];
32422
32423
32424
32425 var CONSTANT_VALUE_REGEXP = /^(true|false|\d+)$/;
32426 /**
32427  * @ngdoc directive
32428  * @name ngValue
32429  *
32430  * @description
32431  * Binds the given expression to the value of `<option>` or {@link input[radio] `input[radio]`},
32432  * so that when the element is selected, the {@link ngModel `ngModel`} of that element is set to
32433  * the bound value.
32434  *
32435  * `ngValue` is useful when dynamically generating lists of radio buttons using
32436  * {@link ngRepeat `ngRepeat`}, as shown below.
32437  *
32438  * Likewise, `ngValue` can be used to generate `<option>` elements for
32439  * the {@link select `select`} element. In that case however, only strings are supported
32440  * for the `value `attribute, so the resulting `ngModel` will always be a string.
32441  * Support for `select` models with non-string values is available via `ngOptions`.
32442  *
32443  * @element input
32444  * @param {string=} ngValue angular expression, whose value will be bound to the `value` attribute
32445  *   of the `input` element
32446  *
32447  * @example
32448     <example name="ngValue-directive" module="valueExample">
32449       <file name="index.html">
32450        <script>
32451           angular.module('valueExample', [])
32452             .controller('ExampleController', ['$scope', function($scope) {
32453               $scope.names = ['pizza', 'unicorns', 'robots'];
32454               $scope.my = { favorite: 'unicorns' };
32455             }]);
32456        </script>
32457         <form ng-controller="ExampleController">
32458           <h2>Which is your favorite?</h2>
32459             <label ng-repeat="name in names" for="{{name}}">
32460               {{name}}
32461               <input type="radio"
32462                      ng-model="my.favorite"
32463                      ng-value="name"
32464                      id="{{name}}"
32465                      name="favorite">
32466             </label>
32467           <div>You chose {{my.favorite}}</div>
32468         </form>
32469       </file>
32470       <file name="protractor.js" type="protractor">
32471         var favorite = element(by.binding('my.favorite'));
32472
32473         it('should initialize to model', function() {
32474           expect(favorite.getText()).toContain('unicorns');
32475         });
32476         it('should bind the values to the inputs', function() {
32477           element.all(by.model('my.favorite')).get(0).click();
32478           expect(favorite.getText()).toContain('pizza');
32479         });
32480       </file>
32481     </example>
32482  */
32483 var ngValueDirective = function() {
32484   return {
32485     restrict: 'A',
32486     priority: 100,
32487     compile: function(tpl, tplAttr) {
32488       if (CONSTANT_VALUE_REGEXP.test(tplAttr.ngValue)) {
32489         return function ngValueConstantLink(scope, elm, attr) {
32490           attr.$set('value', scope.$eval(attr.ngValue));
32491         };
32492       } else {
32493         return function ngValueLink(scope, elm, attr) {
32494           scope.$watch(attr.ngValue, function valueWatchAction(value) {
32495             attr.$set('value', value);
32496           });
32497         };
32498       }
32499     }
32500   };
32501 };
32502
32503 /**
32504  * @ngdoc directive
32505  * @name ngBind
32506  * @restrict AC
32507  *
32508  * @description
32509  * The `ngBind` attribute tells Angular to replace the text content of the specified HTML element
32510  * with the value of a given expression, and to update the text content when the value of that
32511  * expression changes.
32512  *
32513  * Typically, you don't use `ngBind` directly, but instead you use the double curly markup like
32514  * `{{ expression }}` which is similar but less verbose.
32515  *
32516  * It is preferable to use `ngBind` instead of `{{ expression }}` if a template is momentarily
32517  * displayed by the browser in its raw state before Angular compiles it. Since `ngBind` is an
32518  * element attribute, it makes the bindings invisible to the user while the page is loading.
32519  *
32520  * An alternative solution to this problem would be using the
32521  * {@link ng.directive:ngCloak ngCloak} directive.
32522  *
32523  *
32524  * @element ANY
32525  * @param {expression} ngBind {@link guide/expression Expression} to evaluate.
32526  *
32527  * @example
32528  * Enter a name in the Live Preview text box; the greeting below the text box changes instantly.
32529    <example module="bindExample">
32530      <file name="index.html">
32531        <script>
32532          angular.module('bindExample', [])
32533            .controller('ExampleController', ['$scope', function($scope) {
32534              $scope.name = 'Whirled';
32535            }]);
32536        </script>
32537        <div ng-controller="ExampleController">
32538          <label>Enter name: <input type="text" ng-model="name"></label><br>
32539          Hello <span ng-bind="name"></span>!
32540        </div>
32541      </file>
32542      <file name="protractor.js" type="protractor">
32543        it('should check ng-bind', function() {
32544          var nameInput = element(by.model('name'));
32545
32546          expect(element(by.binding('name')).getText()).toBe('Whirled');
32547          nameInput.clear();
32548          nameInput.sendKeys('world');
32549          expect(element(by.binding('name')).getText()).toBe('world');
32550        });
32551      </file>
32552    </example>
32553  */
32554 var ngBindDirective = ['$compile', function($compile) {
32555   return {
32556     restrict: 'AC',
32557     compile: function ngBindCompile(templateElement) {
32558       $compile.$$addBindingClass(templateElement);
32559       return function ngBindLink(scope, element, attr) {
32560         $compile.$$addBindingInfo(element, attr.ngBind);
32561         element = element[0];
32562         scope.$watch(attr.ngBind, function ngBindWatchAction(value) {
32563           element.textContent = isUndefined(value) ? '' : value;
32564         });
32565       };
32566     }
32567   };
32568 }];
32569
32570
32571 /**
32572  * @ngdoc directive
32573  * @name ngBindTemplate
32574  *
32575  * @description
32576  * The `ngBindTemplate` directive specifies that the element
32577  * text content should be replaced with the interpolation of the template
32578  * in the `ngBindTemplate` attribute.
32579  * Unlike `ngBind`, the `ngBindTemplate` can contain multiple `{{` `}}`
32580  * expressions. This directive is needed since some HTML elements
32581  * (such as TITLE and OPTION) cannot contain SPAN elements.
32582  *
32583  * @element ANY
32584  * @param {string} ngBindTemplate template of form
32585  *   <tt>{{</tt> <tt>expression</tt> <tt>}}</tt> to eval.
32586  *
32587  * @example
32588  * Try it here: enter text in text box and watch the greeting change.
32589    <example module="bindExample">
32590      <file name="index.html">
32591        <script>
32592          angular.module('bindExample', [])
32593            .controller('ExampleController', ['$scope', function($scope) {
32594              $scope.salutation = 'Hello';
32595              $scope.name = 'World';
32596            }]);
32597        </script>
32598        <div ng-controller="ExampleController">
32599         <label>Salutation: <input type="text" ng-model="salutation"></label><br>
32600         <label>Name: <input type="text" ng-model="name"></label><br>
32601         <pre ng-bind-template="{{salutation}} {{name}}!"></pre>
32602        </div>
32603      </file>
32604      <file name="protractor.js" type="protractor">
32605        it('should check ng-bind', function() {
32606          var salutationElem = element(by.binding('salutation'));
32607          var salutationInput = element(by.model('salutation'));
32608          var nameInput = element(by.model('name'));
32609
32610          expect(salutationElem.getText()).toBe('Hello World!');
32611
32612          salutationInput.clear();
32613          salutationInput.sendKeys('Greetings');
32614          nameInput.clear();
32615          nameInput.sendKeys('user');
32616
32617          expect(salutationElem.getText()).toBe('Greetings user!');
32618        });
32619      </file>
32620    </example>
32621  */
32622 var ngBindTemplateDirective = ['$interpolate', '$compile', function($interpolate, $compile) {
32623   return {
32624     compile: function ngBindTemplateCompile(templateElement) {
32625       $compile.$$addBindingClass(templateElement);
32626       return function ngBindTemplateLink(scope, element, attr) {
32627         var interpolateFn = $interpolate(element.attr(attr.$attr.ngBindTemplate));
32628         $compile.$$addBindingInfo(element, interpolateFn.expressions);
32629         element = element[0];
32630         attr.$observe('ngBindTemplate', function(value) {
32631           element.textContent = isUndefined(value) ? '' : value;
32632         });
32633       };
32634     }
32635   };
32636 }];
32637
32638
32639 /**
32640  * @ngdoc directive
32641  * @name ngBindHtml
32642  *
32643  * @description
32644  * Evaluates the expression and inserts the resulting HTML into the element in a secure way. By default,
32645  * the resulting HTML content will be sanitized using the {@link ngSanitize.$sanitize $sanitize} service.
32646  * To utilize this functionality, ensure that `$sanitize` is available, for example, by including {@link
32647  * ngSanitize} in your module's dependencies (not in core Angular). In order to use {@link ngSanitize}
32648  * in your module's dependencies, you need to include "angular-sanitize.js" in your application.
32649  *
32650  * You may also bypass sanitization for values you know are safe. To do so, bind to
32651  * an explicitly trusted value via {@link ng.$sce#trustAsHtml $sce.trustAsHtml}.  See the example
32652  * under {@link ng.$sce#show-me-an-example-using-sce- Strict Contextual Escaping (SCE)}.
32653  *
32654  * Note: If a `$sanitize` service is unavailable and the bound value isn't explicitly trusted, you
32655  * will have an exception (instead of an exploit.)
32656  *
32657  * @element ANY
32658  * @param {expression} ngBindHtml {@link guide/expression Expression} to evaluate.
32659  *
32660  * @example
32661
32662    <example module="bindHtmlExample" deps="angular-sanitize.js">
32663      <file name="index.html">
32664        <div ng-controller="ExampleController">
32665         <p ng-bind-html="myHTML"></p>
32666        </div>
32667      </file>
32668
32669      <file name="script.js">
32670        angular.module('bindHtmlExample', ['ngSanitize'])
32671          .controller('ExampleController', ['$scope', function($scope) {
32672            $scope.myHTML =
32673               'I am an <code>HTML</code>string with ' +
32674               '<a href="#">links!</a> and other <em>stuff</em>';
32675          }]);
32676      </file>
32677
32678      <file name="protractor.js" type="protractor">
32679        it('should check ng-bind-html', function() {
32680          expect(element(by.binding('myHTML')).getText()).toBe(
32681              'I am an HTMLstring with links! and other stuff');
32682        });
32683      </file>
32684    </example>
32685  */
32686 var ngBindHtmlDirective = ['$sce', '$parse', '$compile', function($sce, $parse, $compile) {
32687   return {
32688     restrict: 'A',
32689     compile: function ngBindHtmlCompile(tElement, tAttrs) {
32690       var ngBindHtmlGetter = $parse(tAttrs.ngBindHtml);
32691       var ngBindHtmlWatch = $parse(tAttrs.ngBindHtml, function getStringValue(value) {
32692         return (value || '').toString();
32693       });
32694       $compile.$$addBindingClass(tElement);
32695
32696       return function ngBindHtmlLink(scope, element, attr) {
32697         $compile.$$addBindingInfo(element, attr.ngBindHtml);
32698
32699         scope.$watch(ngBindHtmlWatch, function ngBindHtmlWatchAction() {
32700           // we re-evaluate the expr because we want a TrustedValueHolderType
32701           // for $sce, not a string
32702           element.html($sce.getTrustedHtml(ngBindHtmlGetter(scope)) || '');
32703         });
32704       };
32705     }
32706   };
32707 }];
32708
32709 /**
32710  * @ngdoc directive
32711  * @name ngChange
32712  *
32713  * @description
32714  * Evaluate the given expression when the user changes the input.
32715  * The expression is evaluated immediately, unlike the JavaScript onchange event
32716  * which only triggers at the end of a change (usually, when the user leaves the
32717  * form element or presses the return key).
32718  *
32719  * The `ngChange` expression is only evaluated when a change in the input value causes
32720  * a new value to be committed to the model.
32721  *
32722  * It will not be evaluated:
32723  * * if the value returned from the `$parsers` transformation pipeline has not changed
32724  * * if the input has continued to be invalid since the model will stay `null`
32725  * * if the model is changed programmatically and not by a change to the input value
32726  *
32727  *
32728  * Note, this directive requires `ngModel` to be present.
32729  *
32730  * @element input
32731  * @param {expression} ngChange {@link guide/expression Expression} to evaluate upon change
32732  * in input value.
32733  *
32734  * @example
32735  * <example name="ngChange-directive" module="changeExample">
32736  *   <file name="index.html">
32737  *     <script>
32738  *       angular.module('changeExample', [])
32739  *         .controller('ExampleController', ['$scope', function($scope) {
32740  *           $scope.counter = 0;
32741  *           $scope.change = function() {
32742  *             $scope.counter++;
32743  *           };
32744  *         }]);
32745  *     </script>
32746  *     <div ng-controller="ExampleController">
32747  *       <input type="checkbox" ng-model="confirmed" ng-change="change()" id="ng-change-example1" />
32748  *       <input type="checkbox" ng-model="confirmed" id="ng-change-example2" />
32749  *       <label for="ng-change-example2">Confirmed</label><br />
32750  *       <tt>debug = {{confirmed}}</tt><br/>
32751  *       <tt>counter = {{counter}}</tt><br/>
32752  *     </div>
32753  *   </file>
32754  *   <file name="protractor.js" type="protractor">
32755  *     var counter = element(by.binding('counter'));
32756  *     var debug = element(by.binding('confirmed'));
32757  *
32758  *     it('should evaluate the expression if changing from view', function() {
32759  *       expect(counter.getText()).toContain('0');
32760  *
32761  *       element(by.id('ng-change-example1')).click();
32762  *
32763  *       expect(counter.getText()).toContain('1');
32764  *       expect(debug.getText()).toContain('true');
32765  *     });
32766  *
32767  *     it('should not evaluate the expression if changing from model', function() {
32768  *       element(by.id('ng-change-example2')).click();
32769
32770  *       expect(counter.getText()).toContain('0');
32771  *       expect(debug.getText()).toContain('true');
32772  *     });
32773  *   </file>
32774  * </example>
32775  */
32776 var ngChangeDirective = valueFn({
32777   restrict: 'A',
32778   require: 'ngModel',
32779   link: function(scope, element, attr, ctrl) {
32780     ctrl.$viewChangeListeners.push(function() {
32781       scope.$eval(attr.ngChange);
32782     });
32783   }
32784 });
32785
32786 function classDirective(name, selector) {
32787   name = 'ngClass' + name;
32788   return ['$animate', function($animate) {
32789     return {
32790       restrict: 'AC',
32791       link: function(scope, element, attr) {
32792         var oldVal;
32793
32794         scope.$watch(attr[name], ngClassWatchAction, true);
32795
32796         attr.$observe('class', function(value) {
32797           ngClassWatchAction(scope.$eval(attr[name]));
32798         });
32799
32800
32801         if (name !== 'ngClass') {
32802           scope.$watch('$index', function($index, old$index) {
32803             // jshint bitwise: false
32804             var mod = $index & 1;
32805             if (mod !== (old$index & 1)) {
32806               var classes = arrayClasses(scope.$eval(attr[name]));
32807               mod === selector ?
32808                 addClasses(classes) :
32809                 removeClasses(classes);
32810             }
32811           });
32812         }
32813
32814         function addClasses(classes) {
32815           var newClasses = digestClassCounts(classes, 1);
32816           attr.$addClass(newClasses);
32817         }
32818
32819         function removeClasses(classes) {
32820           var newClasses = digestClassCounts(classes, -1);
32821           attr.$removeClass(newClasses);
32822         }
32823
32824         function digestClassCounts(classes, count) {
32825           // Use createMap() to prevent class assumptions involving property
32826           // names in Object.prototype
32827           var classCounts = element.data('$classCounts') || createMap();
32828           var classesToUpdate = [];
32829           forEach(classes, function(className) {
32830             if (count > 0 || classCounts[className]) {
32831               classCounts[className] = (classCounts[className] || 0) + count;
32832               if (classCounts[className] === +(count > 0)) {
32833                 classesToUpdate.push(className);
32834               }
32835             }
32836           });
32837           element.data('$classCounts', classCounts);
32838           return classesToUpdate.join(' ');
32839         }
32840
32841         function updateClasses(oldClasses, newClasses) {
32842           var toAdd = arrayDifference(newClasses, oldClasses);
32843           var toRemove = arrayDifference(oldClasses, newClasses);
32844           toAdd = digestClassCounts(toAdd, 1);
32845           toRemove = digestClassCounts(toRemove, -1);
32846           if (toAdd && toAdd.length) {
32847             $animate.addClass(element, toAdd);
32848           }
32849           if (toRemove && toRemove.length) {
32850             $animate.removeClass(element, toRemove);
32851           }
32852         }
32853
32854         function ngClassWatchAction(newVal) {
32855           if (selector === true || scope.$index % 2 === selector) {
32856             var newClasses = arrayClasses(newVal || []);
32857             if (!oldVal) {
32858               addClasses(newClasses);
32859             } else if (!equals(newVal,oldVal)) {
32860               var oldClasses = arrayClasses(oldVal);
32861               updateClasses(oldClasses, newClasses);
32862             }
32863           }
32864           oldVal = shallowCopy(newVal);
32865         }
32866       }
32867     };
32868
32869     function arrayDifference(tokens1, tokens2) {
32870       var values = [];
32871
32872       outer:
32873       for (var i = 0; i < tokens1.length; i++) {
32874         var token = tokens1[i];
32875         for (var j = 0; j < tokens2.length; j++) {
32876           if (token == tokens2[j]) continue outer;
32877         }
32878         values.push(token);
32879       }
32880       return values;
32881     }
32882
32883     function arrayClasses(classVal) {
32884       var classes = [];
32885       if (isArray(classVal)) {
32886         forEach(classVal, function(v) {
32887           classes = classes.concat(arrayClasses(v));
32888         });
32889         return classes;
32890       } else if (isString(classVal)) {
32891         return classVal.split(' ');
32892       } else if (isObject(classVal)) {
32893         forEach(classVal, function(v, k) {
32894           if (v) {
32895             classes = classes.concat(k.split(' '));
32896           }
32897         });
32898         return classes;
32899       }
32900       return classVal;
32901     }
32902   }];
32903 }
32904
32905 /**
32906  * @ngdoc directive
32907  * @name ngClass
32908  * @restrict AC
32909  *
32910  * @description
32911  * The `ngClass` directive allows you to dynamically set CSS classes on an HTML element by databinding
32912  * an expression that represents all classes to be added.
32913  *
32914  * The directive operates in three different ways, depending on which of three types the expression
32915  * evaluates to:
32916  *
32917  * 1. If the expression evaluates to a string, the string should be one or more space-delimited class
32918  * names.
32919  *
32920  * 2. If the expression evaluates to an object, then for each key-value pair of the
32921  * object with a truthy value the corresponding key is used as a class name.
32922  *
32923  * 3. If the expression evaluates to an array, each element of the array should either be a string as in
32924  * type 1 or an object as in type 2. This means that you can mix strings and objects together in an array
32925  * to give you more control over what CSS classes appear. See the code below for an example of this.
32926  *
32927  *
32928  * The directive won't add duplicate classes if a particular class was already set.
32929  *
32930  * When the expression changes, the previously added classes are removed and only then are the
32931  * new classes added.
32932  *
32933  * @animations
32934  * **add** - happens just before the class is applied to the elements
32935  *
32936  * **remove** - happens just before the class is removed from the element
32937  *
32938  * @element ANY
32939  * @param {expression} ngClass {@link guide/expression Expression} to eval. The result
32940  *   of the evaluation can be a string representing space delimited class
32941  *   names, an array, or a map of class names to boolean values. In the case of a map, the
32942  *   names of the properties whose values are truthy will be added as css classes to the
32943  *   element.
32944  *
32945  * @example Example that demonstrates basic bindings via ngClass directive.
32946    <example>
32947      <file name="index.html">
32948        <p ng-class="{strike: deleted, bold: important, 'has-error': error}">Map Syntax Example</p>
32949        <label>
32950           <input type="checkbox" ng-model="deleted">
32951           deleted (apply "strike" class)
32952        </label><br>
32953        <label>
32954           <input type="checkbox" ng-model="important">
32955           important (apply "bold" class)
32956        </label><br>
32957        <label>
32958           <input type="checkbox" ng-model="error">
32959           error (apply "has-error" class)
32960        </label>
32961        <hr>
32962        <p ng-class="style">Using String Syntax</p>
32963        <input type="text" ng-model="style"
32964               placeholder="Type: bold strike red" aria-label="Type: bold strike red">
32965        <hr>
32966        <p ng-class="[style1, style2, style3]">Using Array Syntax</p>
32967        <input ng-model="style1"
32968               placeholder="Type: bold, strike or red" aria-label="Type: bold, strike or red"><br>
32969        <input ng-model="style2"
32970               placeholder="Type: bold, strike or red" aria-label="Type: bold, strike or red 2"><br>
32971        <input ng-model="style3"
32972               placeholder="Type: bold, strike or red" aria-label="Type: bold, strike or red 3"><br>
32973        <hr>
32974        <p ng-class="[style4, {orange: warning}]">Using Array and Map Syntax</p>
32975        <input ng-model="style4" placeholder="Type: bold, strike" aria-label="Type: bold, strike"><br>
32976        <label><input type="checkbox" ng-model="warning"> warning (apply "orange" class)</label>
32977      </file>
32978      <file name="style.css">
32979        .strike {
32980            text-decoration: line-through;
32981        }
32982        .bold {
32983            font-weight: bold;
32984        }
32985        .red {
32986            color: red;
32987        }
32988        .has-error {
32989            color: red;
32990            background-color: yellow;
32991        }
32992        .orange {
32993            color: orange;
32994        }
32995      </file>
32996      <file name="protractor.js" type="protractor">
32997        var ps = element.all(by.css('p'));
32998
32999        it('should let you toggle the class', function() {
33000
33001          expect(ps.first().getAttribute('class')).not.toMatch(/bold/);
33002          expect(ps.first().getAttribute('class')).not.toMatch(/has-error/);
33003
33004          element(by.model('important')).click();
33005          expect(ps.first().getAttribute('class')).toMatch(/bold/);
33006
33007          element(by.model('error')).click();
33008          expect(ps.first().getAttribute('class')).toMatch(/has-error/);
33009        });
33010
33011        it('should let you toggle string example', function() {
33012          expect(ps.get(1).getAttribute('class')).toBe('');
33013          element(by.model('style')).clear();
33014          element(by.model('style')).sendKeys('red');
33015          expect(ps.get(1).getAttribute('class')).toBe('red');
33016        });
33017
33018        it('array example should have 3 classes', function() {
33019          expect(ps.get(2).getAttribute('class')).toBe('');
33020          element(by.model('style1')).sendKeys('bold');
33021          element(by.model('style2')).sendKeys('strike');
33022          element(by.model('style3')).sendKeys('red');
33023          expect(ps.get(2).getAttribute('class')).toBe('bold strike red');
33024        });
33025
33026        it('array with map example should have 2 classes', function() {
33027          expect(ps.last().getAttribute('class')).toBe('');
33028          element(by.model('style4')).sendKeys('bold');
33029          element(by.model('warning')).click();
33030          expect(ps.last().getAttribute('class')).toBe('bold orange');
33031        });
33032      </file>
33033    </example>
33034
33035    ## Animations
33036
33037    The example below demonstrates how to perform animations using ngClass.
33038
33039    <example module="ngAnimate" deps="angular-animate.js" animations="true">
33040      <file name="index.html">
33041       <input id="setbtn" type="button" value="set" ng-click="myVar='my-class'">
33042       <input id="clearbtn" type="button" value="clear" ng-click="myVar=''">
33043       <br>
33044       <span class="base-class" ng-class="myVar">Sample Text</span>
33045      </file>
33046      <file name="style.css">
33047        .base-class {
33048          transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
33049        }
33050
33051        .base-class.my-class {
33052          color: red;
33053          font-size:3em;
33054        }
33055      </file>
33056      <file name="protractor.js" type="protractor">
33057        it('should check ng-class', function() {
33058          expect(element(by.css('.base-class')).getAttribute('class')).not.
33059            toMatch(/my-class/);
33060
33061          element(by.id('setbtn')).click();
33062
33063          expect(element(by.css('.base-class')).getAttribute('class')).
33064            toMatch(/my-class/);
33065
33066          element(by.id('clearbtn')).click();
33067
33068          expect(element(by.css('.base-class')).getAttribute('class')).not.
33069            toMatch(/my-class/);
33070        });
33071      </file>
33072    </example>
33073
33074
33075    ## ngClass and pre-existing CSS3 Transitions/Animations
33076    The ngClass directive still supports CSS3 Transitions/Animations even if they do not follow the ngAnimate CSS naming structure.
33077    Upon animation ngAnimate will apply supplementary CSS classes to track the start and end of an animation, but this will not hinder
33078    any pre-existing CSS transitions already on the element. To get an idea of what happens during a class-based animation, be sure
33079    to view the step by step details of {@link $animate#addClass $animate.addClass} and
33080    {@link $animate#removeClass $animate.removeClass}.
33081  */
33082 var ngClassDirective = classDirective('', true);
33083
33084 /**
33085  * @ngdoc directive
33086  * @name ngClassOdd
33087  * @restrict AC
33088  *
33089  * @description
33090  * The `ngClassOdd` and `ngClassEven` directives work exactly as
33091  * {@link ng.directive:ngClass ngClass}, except they work in
33092  * conjunction with `ngRepeat` and take effect only on odd (even) rows.
33093  *
33094  * This directive can be applied only within the scope of an
33095  * {@link ng.directive:ngRepeat ngRepeat}.
33096  *
33097  * @element ANY
33098  * @param {expression} ngClassOdd {@link guide/expression Expression} to eval. The result
33099  *   of the evaluation can be a string representing space delimited class names or an array.
33100  *
33101  * @example
33102    <example>
33103      <file name="index.html">
33104         <ol ng-init="names=['John', 'Mary', 'Cate', 'Suz']">
33105           <li ng-repeat="name in names">
33106            <span ng-class-odd="'odd'" ng-class-even="'even'">
33107              {{name}}
33108            </span>
33109           </li>
33110         </ol>
33111      </file>
33112      <file name="style.css">
33113        .odd {
33114          color: red;
33115        }
33116        .even {
33117          color: blue;
33118        }
33119      </file>
33120      <file name="protractor.js" type="protractor">
33121        it('should check ng-class-odd and ng-class-even', function() {
33122          expect(element(by.repeater('name in names').row(0).column('name')).getAttribute('class')).
33123            toMatch(/odd/);
33124          expect(element(by.repeater('name in names').row(1).column('name')).getAttribute('class')).
33125            toMatch(/even/);
33126        });
33127      </file>
33128    </example>
33129  */
33130 var ngClassOddDirective = classDirective('Odd', 0);
33131
33132 /**
33133  * @ngdoc directive
33134  * @name ngClassEven
33135  * @restrict AC
33136  *
33137  * @description
33138  * The `ngClassOdd` and `ngClassEven` directives work exactly as
33139  * {@link ng.directive:ngClass ngClass}, except they work in
33140  * conjunction with `ngRepeat` and take effect only on odd (even) rows.
33141  *
33142  * This directive can be applied only within the scope of an
33143  * {@link ng.directive:ngRepeat ngRepeat}.
33144  *
33145  * @element ANY
33146  * @param {expression} ngClassEven {@link guide/expression Expression} to eval. The
33147  *   result of the evaluation can be a string representing space delimited class names or an array.
33148  *
33149  * @example
33150    <example>
33151      <file name="index.html">
33152         <ol ng-init="names=['John', 'Mary', 'Cate', 'Suz']">
33153           <li ng-repeat="name in names">
33154            <span ng-class-odd="'odd'" ng-class-even="'even'">
33155              {{name}} &nbsp; &nbsp; &nbsp;
33156            </span>
33157           </li>
33158         </ol>
33159      </file>
33160      <file name="style.css">
33161        .odd {
33162          color: red;
33163        }
33164        .even {
33165          color: blue;
33166        }
33167      </file>
33168      <file name="protractor.js" type="protractor">
33169        it('should check ng-class-odd and ng-class-even', function() {
33170          expect(element(by.repeater('name in names').row(0).column('name')).getAttribute('class')).
33171            toMatch(/odd/);
33172          expect(element(by.repeater('name in names').row(1).column('name')).getAttribute('class')).
33173            toMatch(/even/);
33174        });
33175      </file>
33176    </example>
33177  */
33178 var ngClassEvenDirective = classDirective('Even', 1);
33179
33180 /**
33181  * @ngdoc directive
33182  * @name ngCloak
33183  * @restrict AC
33184  *
33185  * @description
33186  * The `ngCloak` directive is used to prevent the Angular html template from being briefly
33187  * displayed by the browser in its raw (uncompiled) form while your application is loading. Use this
33188  * directive to avoid the undesirable flicker effect caused by the html template display.
33189  *
33190  * The directive can be applied to the `<body>` element, but the preferred usage is to apply
33191  * multiple `ngCloak` directives to small portions of the page to permit progressive rendering
33192  * of the browser view.
33193  *
33194  * `ngCloak` works in cooperation with the following css rule embedded within `angular.js` and
33195  * `angular.min.js`.
33196  * For CSP mode please add `angular-csp.css` to your html file (see {@link ng.directive:ngCsp ngCsp}).
33197  *
33198  * ```css
33199  * [ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak {
33200  *   display: none !important;
33201  * }
33202  * ```
33203  *
33204  * When this css rule is loaded by the browser, all html elements (including their children) that
33205  * are tagged with the `ngCloak` directive are hidden. When Angular encounters this directive
33206  * during the compilation of the template it deletes the `ngCloak` element attribute, making
33207  * the compiled element visible.
33208  *
33209  * For the best result, the `angular.js` script must be loaded in the head section of the html
33210  * document; alternatively, the css rule above must be included in the external stylesheet of the
33211  * application.
33212  *
33213  * @element ANY
33214  *
33215  * @example
33216    <example>
33217      <file name="index.html">
33218         <div id="template1" ng-cloak>{{ 'hello' }}</div>
33219         <div id="template2" class="ng-cloak">{{ 'world' }}</div>
33220      </file>
33221      <file name="protractor.js" type="protractor">
33222        it('should remove the template directive and css class', function() {
33223          expect($('#template1').getAttribute('ng-cloak')).
33224            toBeNull();
33225          expect($('#template2').getAttribute('ng-cloak')).
33226            toBeNull();
33227        });
33228      </file>
33229    </example>
33230  *
33231  */
33232 var ngCloakDirective = ngDirective({
33233   compile: function(element, attr) {
33234     attr.$set('ngCloak', undefined);
33235     element.removeClass('ng-cloak');
33236   }
33237 });
33238
33239 /**
33240  * @ngdoc directive
33241  * @name ngController
33242  *
33243  * @description
33244  * The `ngController` directive attaches a controller class to the view. This is a key aspect of how angular
33245  * supports the principles behind the Model-View-Controller design pattern.
33246  *
33247  * MVC components in angular:
33248  *
33249  * * Model — Models are the properties of a scope; scopes are attached to the DOM where scope properties
33250  *   are accessed through bindings.
33251  * * View — The template (HTML with data bindings) that is rendered into the View.
33252  * * Controller — The `ngController` directive specifies a Controller class; the class contains business
33253  *   logic behind the application to decorate the scope with functions and values
33254  *
33255  * Note that you can also attach controllers to the DOM by declaring it in a route definition
33256  * via the {@link ngRoute.$route $route} service. A common mistake is to declare the controller
33257  * again using `ng-controller` in the template itself.  This will cause the controller to be attached
33258  * and executed twice.
33259  *
33260  * @element ANY
33261  * @scope
33262  * @priority 500
33263  * @param {expression} ngController Name of a constructor function registered with the current
33264  * {@link ng.$controllerProvider $controllerProvider} or an {@link guide/expression expression}
33265  * that on the current scope evaluates to a constructor function.
33266  *
33267  * The controller instance can be published into a scope property by specifying
33268  * `ng-controller="as propertyName"`.
33269  *
33270  * If the current `$controllerProvider` is configured to use globals (via
33271  * {@link ng.$controllerProvider#allowGlobals `$controllerProvider.allowGlobals()` }), this may
33272  * also be the name of a globally accessible constructor function (not recommended).
33273  *
33274  * @example
33275  * Here is a simple form for editing user contact information. Adding, removing, clearing, and
33276  * greeting are methods declared on the controller (see source tab). These methods can
33277  * easily be called from the angular markup. Any changes to the data are automatically reflected
33278  * in the View without the need for a manual update.
33279  *
33280  * Two different declaration styles are included below:
33281  *
33282  * * one binds methods and properties directly onto the controller using `this`:
33283  * `ng-controller="SettingsController1 as settings"`
33284  * * one injects `$scope` into the controller:
33285  * `ng-controller="SettingsController2"`
33286  *
33287  * The second option is more common in the Angular community, and is generally used in boilerplates
33288  * and in this guide. However, there are advantages to binding properties directly to the controller
33289  * and avoiding scope.
33290  *
33291  * * Using `controller as` makes it obvious which controller you are accessing in the template when
33292  * multiple controllers apply to an element.
33293  * * If you are writing your controllers as classes you have easier access to the properties and
33294  * methods, which will appear on the scope, from inside the controller code.
33295  * * Since there is always a `.` in the bindings, you don't have to worry about prototypal
33296  * inheritance masking primitives.
33297  *
33298  * This example demonstrates the `controller as` syntax.
33299  *
33300  * <example name="ngControllerAs" module="controllerAsExample">
33301  *   <file name="index.html">
33302  *    <div id="ctrl-as-exmpl" ng-controller="SettingsController1 as settings">
33303  *      <label>Name: <input type="text" ng-model="settings.name"/></label>
33304  *      <button ng-click="settings.greet()">greet</button><br/>
33305  *      Contact:
33306  *      <ul>
33307  *        <li ng-repeat="contact in settings.contacts">
33308  *          <select ng-model="contact.type" aria-label="Contact method" id="select_{{$index}}">
33309  *             <option>phone</option>
33310  *             <option>email</option>
33311  *          </select>
33312  *          <input type="text" ng-model="contact.value" aria-labelledby="select_{{$index}}" />
33313  *          <button ng-click="settings.clearContact(contact)">clear</button>
33314  *          <button ng-click="settings.removeContact(contact)" aria-label="Remove">X</button>
33315  *        </li>
33316  *        <li><button ng-click="settings.addContact()">add</button></li>
33317  *     </ul>
33318  *    </div>
33319  *   </file>
33320  *   <file name="app.js">
33321  *    angular.module('controllerAsExample', [])
33322  *      .controller('SettingsController1', SettingsController1);
33323  *
33324  *    function SettingsController1() {
33325  *      this.name = "John Smith";
33326  *      this.contacts = [
33327  *        {type: 'phone', value: '408 555 1212'},
33328  *        {type: 'email', value: 'john.smith@example.org'} ];
33329  *    }
33330  *
33331  *    SettingsController1.prototype.greet = function() {
33332  *      alert(this.name);
33333  *    };
33334  *
33335  *    SettingsController1.prototype.addContact = function() {
33336  *      this.contacts.push({type: 'email', value: 'yourname@example.org'});
33337  *    };
33338  *
33339  *    SettingsController1.prototype.removeContact = function(contactToRemove) {
33340  *     var index = this.contacts.indexOf(contactToRemove);
33341  *      this.contacts.splice(index, 1);
33342  *    };
33343  *
33344  *    SettingsController1.prototype.clearContact = function(contact) {
33345  *      contact.type = 'phone';
33346  *      contact.value = '';
33347  *    };
33348  *   </file>
33349  *   <file name="protractor.js" type="protractor">
33350  *     it('should check controller as', function() {
33351  *       var container = element(by.id('ctrl-as-exmpl'));
33352  *         expect(container.element(by.model('settings.name'))
33353  *           .getAttribute('value')).toBe('John Smith');
33354  *
33355  *       var firstRepeat =
33356  *           container.element(by.repeater('contact in settings.contacts').row(0));
33357  *       var secondRepeat =
33358  *           container.element(by.repeater('contact in settings.contacts').row(1));
33359  *
33360  *       expect(firstRepeat.element(by.model('contact.value')).getAttribute('value'))
33361  *           .toBe('408 555 1212');
33362  *
33363  *       expect(secondRepeat.element(by.model('contact.value')).getAttribute('value'))
33364  *           .toBe('john.smith@example.org');
33365  *
33366  *       firstRepeat.element(by.buttonText('clear')).click();
33367  *
33368  *       expect(firstRepeat.element(by.model('contact.value')).getAttribute('value'))
33369  *           .toBe('');
33370  *
33371  *       container.element(by.buttonText('add')).click();
33372  *
33373  *       expect(container.element(by.repeater('contact in settings.contacts').row(2))
33374  *           .element(by.model('contact.value'))
33375  *           .getAttribute('value'))
33376  *           .toBe('yourname@example.org');
33377  *     });
33378  *   </file>
33379  * </example>
33380  *
33381  * This example demonstrates the "attach to `$scope`" style of controller.
33382  *
33383  * <example name="ngController" module="controllerExample">
33384  *  <file name="index.html">
33385  *   <div id="ctrl-exmpl" ng-controller="SettingsController2">
33386  *     <label>Name: <input type="text" ng-model="name"/></label>
33387  *     <button ng-click="greet()">greet</button><br/>
33388  *     Contact:
33389  *     <ul>
33390  *       <li ng-repeat="contact in contacts">
33391  *         <select ng-model="contact.type" id="select_{{$index}}">
33392  *            <option>phone</option>
33393  *            <option>email</option>
33394  *         </select>
33395  *         <input type="text" ng-model="contact.value" aria-labelledby="select_{{$index}}" />
33396  *         <button ng-click="clearContact(contact)">clear</button>
33397  *         <button ng-click="removeContact(contact)">X</button>
33398  *       </li>
33399  *       <li>[ <button ng-click="addContact()">add</button> ]</li>
33400  *    </ul>
33401  *   </div>
33402  *  </file>
33403  *  <file name="app.js">
33404  *   angular.module('controllerExample', [])
33405  *     .controller('SettingsController2', ['$scope', SettingsController2]);
33406  *
33407  *   function SettingsController2($scope) {
33408  *     $scope.name = "John Smith";
33409  *     $scope.contacts = [
33410  *       {type:'phone', value:'408 555 1212'},
33411  *       {type:'email', value:'john.smith@example.org'} ];
33412  *
33413  *     $scope.greet = function() {
33414  *       alert($scope.name);
33415  *     };
33416  *
33417  *     $scope.addContact = function() {
33418  *       $scope.contacts.push({type:'email', value:'yourname@example.org'});
33419  *     };
33420  *
33421  *     $scope.removeContact = function(contactToRemove) {
33422  *       var index = $scope.contacts.indexOf(contactToRemove);
33423  *       $scope.contacts.splice(index, 1);
33424  *     };
33425  *
33426  *     $scope.clearContact = function(contact) {
33427  *       contact.type = 'phone';
33428  *       contact.value = '';
33429  *     };
33430  *   }
33431  *  </file>
33432  *  <file name="protractor.js" type="protractor">
33433  *    it('should check controller', function() {
33434  *      var container = element(by.id('ctrl-exmpl'));
33435  *
33436  *      expect(container.element(by.model('name'))
33437  *          .getAttribute('value')).toBe('John Smith');
33438  *
33439  *      var firstRepeat =
33440  *          container.element(by.repeater('contact in contacts').row(0));
33441  *      var secondRepeat =
33442  *          container.element(by.repeater('contact in contacts').row(1));
33443  *
33444  *      expect(firstRepeat.element(by.model('contact.value')).getAttribute('value'))
33445  *          .toBe('408 555 1212');
33446  *      expect(secondRepeat.element(by.model('contact.value')).getAttribute('value'))
33447  *          .toBe('john.smith@example.org');
33448  *
33449  *      firstRepeat.element(by.buttonText('clear')).click();
33450  *
33451  *      expect(firstRepeat.element(by.model('contact.value')).getAttribute('value'))
33452  *          .toBe('');
33453  *
33454  *      container.element(by.buttonText('add')).click();
33455  *
33456  *      expect(container.element(by.repeater('contact in contacts').row(2))
33457  *          .element(by.model('contact.value'))
33458  *          .getAttribute('value'))
33459  *          .toBe('yourname@example.org');
33460  *    });
33461  *  </file>
33462  *</example>
33463
33464  */
33465 var ngControllerDirective = [function() {
33466   return {
33467     restrict: 'A',
33468     scope: true,
33469     controller: '@',
33470     priority: 500
33471   };
33472 }];
33473
33474 /**
33475  * @ngdoc directive
33476  * @name ngCsp
33477  *
33478  * @element html
33479  * @description
33480  *
33481  * Angular has some features that can break certain
33482  * [CSP (Content Security Policy)](https://developer.mozilla.org/en/Security/CSP) rules.
33483  *
33484  * If you intend to implement these rules then you must tell Angular not to use these features.
33485  *
33486  * This is necessary when developing things like Google Chrome Extensions or Universal Windows Apps.
33487  *
33488  *
33489  * The following rules affect Angular:
33490  *
33491  * * `unsafe-eval`: this rule forbids apps to use `eval` or `Function(string)` generated functions
33492  * (among other things). Angular makes use of this in the {@link $parse} service to provide a 30%
33493  * increase in the speed of evaluating Angular expressions.
33494  *
33495  * * `unsafe-inline`: this rule forbids apps from inject custom styles into the document. Angular
33496  * makes use of this to include some CSS rules (e.g. {@link ngCloak} and {@link ngHide}).
33497  * To make these directives work when a CSP rule is blocking inline styles, you must link to the
33498  * `angular-csp.css` in your HTML manually.
33499  *
33500  * If you do not provide `ngCsp` then Angular tries to autodetect if CSP is blocking unsafe-eval
33501  * and automatically deactivates this feature in the {@link $parse} service. This autodetection,
33502  * however, triggers a CSP error to be logged in the console:
33503  *
33504  * ```
33505  * Refused to evaluate a string as JavaScript because 'unsafe-eval' is not an allowed source of
33506  * script in the following Content Security Policy directive: "default-src 'self'". Note that
33507  * 'script-src' was not explicitly set, so 'default-src' is used as a fallback.
33508  * ```
33509  *
33510  * This error is harmless but annoying. To prevent the error from showing up, put the `ngCsp`
33511  * directive on an element of the HTML document that appears before the `<script>` tag that loads
33512  * the `angular.js` file.
33513  *
33514  * *Note: This directive is only available in the `ng-csp` and `data-ng-csp` attribute form.*
33515  *
33516  * You can specify which of the CSP related Angular features should be deactivated by providing
33517  * a value for the `ng-csp` attribute. The options are as follows:
33518  *
33519  * * no-inline-style: this stops Angular from injecting CSS styles into the DOM
33520  *
33521  * * no-unsafe-eval: this stops Angular from optimizing $parse with unsafe eval of strings
33522  *
33523  * You can use these values in the following combinations:
33524  *
33525  *
33526  * * No declaration means that Angular will assume that you can do inline styles, but it will do
33527  * a runtime check for unsafe-eval. E.g. `<body>`. This is backwardly compatible with previous versions
33528  * of Angular.
33529  *
33530  * * A simple `ng-csp` (or `data-ng-csp`) attribute will tell Angular to deactivate both inline
33531  * styles and unsafe eval. E.g. `<body ng-csp>`. This is backwardly compatible with previous versions
33532  * of Angular.
33533  *
33534  * * Specifying only `no-unsafe-eval` tells Angular that we must not use eval, but that we can inject
33535  * inline styles. E.g. `<body ng-csp="no-unsafe-eval">`.
33536  *
33537  * * Specifying only `no-inline-style` tells Angular that we must not inject styles, but that we can
33538  * run eval - no automatic check for unsafe eval will occur. E.g. `<body ng-csp="no-inline-style">`
33539  *
33540  * * Specifying both `no-unsafe-eval` and `no-inline-style` tells Angular that we must not inject
33541  * styles nor use eval, which is the same as an empty: ng-csp.
33542  * E.g.`<body ng-csp="no-inline-style;no-unsafe-eval">`
33543  *
33544  * @example
33545  * This example shows how to apply the `ngCsp` directive to the `html` tag.
33546    ```html
33547      <!doctype html>
33548      <html ng-app ng-csp>
33549      ...
33550      ...
33551      </html>
33552    ```
33553   * @example
33554       // Note: the suffix `.csp` in the example name triggers
33555       // csp mode in our http server!
33556       <example name="example.csp" module="cspExample" ng-csp="true">
33557         <file name="index.html">
33558           <div ng-controller="MainController as ctrl">
33559             <div>
33560               <button ng-click="ctrl.inc()" id="inc">Increment</button>
33561               <span id="counter">
33562                 {{ctrl.counter}}
33563               </span>
33564             </div>
33565
33566             <div>
33567               <button ng-click="ctrl.evil()" id="evil">Evil</button>
33568               <span id="evilError">
33569                 {{ctrl.evilError}}
33570               </span>
33571             </div>
33572           </div>
33573         </file>
33574         <file name="script.js">
33575            angular.module('cspExample', [])
33576              .controller('MainController', function() {
33577                 this.counter = 0;
33578                 this.inc = function() {
33579                   this.counter++;
33580                 };
33581                 this.evil = function() {
33582                   // jshint evil:true
33583                   try {
33584                     eval('1+2');
33585                   } catch (e) {
33586                     this.evilError = e.message;
33587                   }
33588                 };
33589               });
33590         </file>
33591         <file name="protractor.js" type="protractor">
33592           var util, webdriver;
33593
33594           var incBtn = element(by.id('inc'));
33595           var counter = element(by.id('counter'));
33596           var evilBtn = element(by.id('evil'));
33597           var evilError = element(by.id('evilError'));
33598
33599           function getAndClearSevereErrors() {
33600             return browser.manage().logs().get('browser').then(function(browserLog) {
33601               return browserLog.filter(function(logEntry) {
33602                 return logEntry.level.value > webdriver.logging.Level.WARNING.value;
33603               });
33604             });
33605           }
33606
33607           function clearErrors() {
33608             getAndClearSevereErrors();
33609           }
33610
33611           function expectNoErrors() {
33612             getAndClearSevereErrors().then(function(filteredLog) {
33613               expect(filteredLog.length).toEqual(0);
33614               if (filteredLog.length) {
33615                 console.log('browser console errors: ' + util.inspect(filteredLog));
33616               }
33617             });
33618           }
33619
33620           function expectError(regex) {
33621             getAndClearSevereErrors().then(function(filteredLog) {
33622               var found = false;
33623               filteredLog.forEach(function(log) {
33624                 if (log.message.match(regex)) {
33625                   found = true;
33626                 }
33627               });
33628               if (!found) {
33629                 throw new Error('expected an error that matches ' + regex);
33630               }
33631             });
33632           }
33633
33634           beforeEach(function() {
33635             util = require('util');
33636             webdriver = require('protractor/node_modules/selenium-webdriver');
33637           });
33638
33639           // For now, we only test on Chrome,
33640           // as Safari does not load the page with Protractor's injected scripts,
33641           // and Firefox webdriver always disables content security policy (#6358)
33642           if (browser.params.browser !== 'chrome') {
33643             return;
33644           }
33645
33646           it('should not report errors when the page is loaded', function() {
33647             // clear errors so we are not dependent on previous tests
33648             clearErrors();
33649             // Need to reload the page as the page is already loaded when
33650             // we come here
33651             browser.driver.getCurrentUrl().then(function(url) {
33652               browser.get(url);
33653             });
33654             expectNoErrors();
33655           });
33656
33657           it('should evaluate expressions', function() {
33658             expect(counter.getText()).toEqual('0');
33659             incBtn.click();
33660             expect(counter.getText()).toEqual('1');
33661             expectNoErrors();
33662           });
33663
33664           it('should throw and report an error when using "eval"', function() {
33665             evilBtn.click();
33666             expect(evilError.getText()).toMatch(/Content Security Policy/);
33667             expectError(/Content Security Policy/);
33668           });
33669         </file>
33670       </example>
33671   */
33672
33673 // ngCsp is not implemented as a proper directive any more, because we need it be processed while we
33674 // bootstrap the system (before $parse is instantiated), for this reason we just have
33675 // the csp() fn that looks for the `ng-csp` attribute anywhere in the current doc
33676
33677 /**
33678  * @ngdoc directive
33679  * @name ngClick
33680  *
33681  * @description
33682  * The ngClick directive allows you to specify custom behavior when
33683  * an element is clicked.
33684  *
33685  * @element ANY
33686  * @priority 0
33687  * @param {expression} ngClick {@link guide/expression Expression} to evaluate upon
33688  * click. ({@link guide/expression#-event- Event object is available as `$event`})
33689  *
33690  * @example
33691    <example>
33692      <file name="index.html">
33693       <button ng-click="count = count + 1" ng-init="count=0">
33694         Increment
33695       </button>
33696       <span>
33697         count: {{count}}
33698       </span>
33699      </file>
33700      <file name="protractor.js" type="protractor">
33701        it('should check ng-click', function() {
33702          expect(element(by.binding('count')).getText()).toMatch('0');
33703          element(by.css('button')).click();
33704          expect(element(by.binding('count')).getText()).toMatch('1');
33705        });
33706      </file>
33707    </example>
33708  */
33709 /*
33710  * A collection of directives that allows creation of custom event handlers that are defined as
33711  * angular expressions and are compiled and executed within the current scope.
33712  */
33713 var ngEventDirectives = {};
33714
33715 // For events that might fire synchronously during DOM manipulation
33716 // we need to execute their event handlers asynchronously using $evalAsync,
33717 // so that they are not executed in an inconsistent state.
33718 var forceAsyncEvents = {
33719   'blur': true,
33720   'focus': true
33721 };
33722 forEach(
33723   'click dblclick mousedown mouseup mouseover mouseout mousemove mouseenter mouseleave keydown keyup keypress submit focus blur copy cut paste'.split(' '),
33724   function(eventName) {
33725     var directiveName = directiveNormalize('ng-' + eventName);
33726     ngEventDirectives[directiveName] = ['$parse', '$rootScope', function($parse, $rootScope) {
33727       return {
33728         restrict: 'A',
33729         compile: function($element, attr) {
33730           // We expose the powerful $event object on the scope that provides access to the Window,
33731           // etc. that isn't protected by the fast paths in $parse.  We explicitly request better
33732           // checks at the cost of speed since event handler expressions are not executed as
33733           // frequently as regular change detection.
33734           var fn = $parse(attr[directiveName], /* interceptorFn */ null, /* expensiveChecks */ true);
33735           return function ngEventHandler(scope, element) {
33736             element.on(eventName, function(event) {
33737               var callback = function() {
33738                 fn(scope, {$event:event});
33739               };
33740               if (forceAsyncEvents[eventName] && $rootScope.$$phase) {
33741                 scope.$evalAsync(callback);
33742               } else {
33743                 scope.$apply(callback);
33744               }
33745             });
33746           };
33747         }
33748       };
33749     }];
33750   }
33751 );
33752
33753 /**
33754  * @ngdoc directive
33755  * @name ngDblclick
33756  *
33757  * @description
33758  * The `ngDblclick` directive allows you to specify custom behavior on a dblclick event.
33759  *
33760  * @element ANY
33761  * @priority 0
33762  * @param {expression} ngDblclick {@link guide/expression Expression} to evaluate upon
33763  * a dblclick. (The Event object is available as `$event`)
33764  *
33765  * @example
33766    <example>
33767      <file name="index.html">
33768       <button ng-dblclick="count = count + 1" ng-init="count=0">
33769         Increment (on double click)
33770       </button>
33771       count: {{count}}
33772      </file>
33773    </example>
33774  */
33775
33776
33777 /**
33778  * @ngdoc directive
33779  * @name ngMousedown
33780  *
33781  * @description
33782  * The ngMousedown directive allows you to specify custom behavior on mousedown event.
33783  *
33784  * @element ANY
33785  * @priority 0
33786  * @param {expression} ngMousedown {@link guide/expression Expression} to evaluate upon
33787  * mousedown. ({@link guide/expression#-event- Event object is available as `$event`})
33788  *
33789  * @example
33790    <example>
33791      <file name="index.html">
33792       <button ng-mousedown="count = count + 1" ng-init="count=0">
33793         Increment (on mouse down)
33794       </button>
33795       count: {{count}}
33796      </file>
33797    </example>
33798  */
33799
33800
33801 /**
33802  * @ngdoc directive
33803  * @name ngMouseup
33804  *
33805  * @description
33806  * Specify custom behavior on mouseup event.
33807  *
33808  * @element ANY
33809  * @priority 0
33810  * @param {expression} ngMouseup {@link guide/expression Expression} to evaluate upon
33811  * mouseup. ({@link guide/expression#-event- Event object is available as `$event`})
33812  *
33813  * @example
33814    <example>
33815      <file name="index.html">
33816       <button ng-mouseup="count = count + 1" ng-init="count=0">
33817         Increment (on mouse up)
33818       </button>
33819       count: {{count}}
33820      </file>
33821    </example>
33822  */
33823
33824 /**
33825  * @ngdoc directive
33826  * @name ngMouseover
33827  *
33828  * @description
33829  * Specify custom behavior on mouseover event.
33830  *
33831  * @element ANY
33832  * @priority 0
33833  * @param {expression} ngMouseover {@link guide/expression Expression} to evaluate upon
33834  * mouseover. ({@link guide/expression#-event- Event object is available as `$event`})
33835  *
33836  * @example
33837    <example>
33838      <file name="index.html">
33839       <button ng-mouseover="count = count + 1" ng-init="count=0">
33840         Increment (when mouse is over)
33841       </button>
33842       count: {{count}}
33843      </file>
33844    </example>
33845  */
33846
33847
33848 /**
33849  * @ngdoc directive
33850  * @name ngMouseenter
33851  *
33852  * @description
33853  * Specify custom behavior on mouseenter event.
33854  *
33855  * @element ANY
33856  * @priority 0
33857  * @param {expression} ngMouseenter {@link guide/expression Expression} to evaluate upon
33858  * mouseenter. ({@link guide/expression#-event- Event object is available as `$event`})
33859  *
33860  * @example
33861    <example>
33862      <file name="index.html">
33863       <button ng-mouseenter="count = count + 1" ng-init="count=0">
33864         Increment (when mouse enters)
33865       </button>
33866       count: {{count}}
33867      </file>
33868    </example>
33869  */
33870
33871
33872 /**
33873  * @ngdoc directive
33874  * @name ngMouseleave
33875  *
33876  * @description
33877  * Specify custom behavior on mouseleave event.
33878  *
33879  * @element ANY
33880  * @priority 0
33881  * @param {expression} ngMouseleave {@link guide/expression Expression} to evaluate upon
33882  * mouseleave. ({@link guide/expression#-event- Event object is available as `$event`})
33883  *
33884  * @example
33885    <example>
33886      <file name="index.html">
33887       <button ng-mouseleave="count = count + 1" ng-init="count=0">
33888         Increment (when mouse leaves)
33889       </button>
33890       count: {{count}}
33891      </file>
33892    </example>
33893  */
33894
33895
33896 /**
33897  * @ngdoc directive
33898  * @name ngMousemove
33899  *
33900  * @description
33901  * Specify custom behavior on mousemove event.
33902  *
33903  * @element ANY
33904  * @priority 0
33905  * @param {expression} ngMousemove {@link guide/expression Expression} to evaluate upon
33906  * mousemove. ({@link guide/expression#-event- Event object is available as `$event`})
33907  *
33908  * @example
33909    <example>
33910      <file name="index.html">
33911       <button ng-mousemove="count = count + 1" ng-init="count=0">
33912         Increment (when mouse moves)
33913       </button>
33914       count: {{count}}
33915      </file>
33916    </example>
33917  */
33918
33919
33920 /**
33921  * @ngdoc directive
33922  * @name ngKeydown
33923  *
33924  * @description
33925  * Specify custom behavior on keydown event.
33926  *
33927  * @element ANY
33928  * @priority 0
33929  * @param {expression} ngKeydown {@link guide/expression Expression} to evaluate upon
33930  * keydown. (Event object is available as `$event` and can be interrogated for keyCode, altKey, etc.)
33931  *
33932  * @example
33933    <example>
33934      <file name="index.html">
33935       <input ng-keydown="count = count + 1" ng-init="count=0">
33936       key down count: {{count}}
33937      </file>
33938    </example>
33939  */
33940
33941
33942 /**
33943  * @ngdoc directive
33944  * @name ngKeyup
33945  *
33946  * @description
33947  * Specify custom behavior on keyup event.
33948  *
33949  * @element ANY
33950  * @priority 0
33951  * @param {expression} ngKeyup {@link guide/expression Expression} to evaluate upon
33952  * keyup. (Event object is available as `$event` and can be interrogated for keyCode, altKey, etc.)
33953  *
33954  * @example
33955    <example>
33956      <file name="index.html">
33957        <p>Typing in the input box below updates the key count</p>
33958        <input ng-keyup="count = count + 1" ng-init="count=0"> key up count: {{count}}
33959
33960        <p>Typing in the input box below updates the keycode</p>
33961        <input ng-keyup="event=$event">
33962        <p>event keyCode: {{ event.keyCode }}</p>
33963        <p>event altKey: {{ event.altKey }}</p>
33964      </file>
33965    </example>
33966  */
33967
33968
33969 /**
33970  * @ngdoc directive
33971  * @name ngKeypress
33972  *
33973  * @description
33974  * Specify custom behavior on keypress event.
33975  *
33976  * @element ANY
33977  * @param {expression} ngKeypress {@link guide/expression Expression} to evaluate upon
33978  * keypress. ({@link guide/expression#-event- Event object is available as `$event`}
33979  * and can be interrogated for keyCode, altKey, etc.)
33980  *
33981  * @example
33982    <example>
33983      <file name="index.html">
33984       <input ng-keypress="count = count + 1" ng-init="count=0">
33985       key press count: {{count}}
33986      </file>
33987    </example>
33988  */
33989
33990
33991 /**
33992  * @ngdoc directive
33993  * @name ngSubmit
33994  *
33995  * @description
33996  * Enables binding angular expressions to onsubmit events.
33997  *
33998  * Additionally it prevents the default action (which for form means sending the request to the
33999  * server and reloading the current page), but only if the form does not contain `action`,
34000  * `data-action`, or `x-action` attributes.
34001  *
34002  * <div class="alert alert-warning">
34003  * **Warning:** Be careful not to cause "double-submission" by using both the `ngClick` and
34004  * `ngSubmit` handlers together. See the
34005  * {@link form#submitting-a-form-and-preventing-the-default-action `form` directive documentation}
34006  * for a detailed discussion of when `ngSubmit` may be triggered.
34007  * </div>
34008  *
34009  * @element form
34010  * @priority 0
34011  * @param {expression} ngSubmit {@link guide/expression Expression} to eval.
34012  * ({@link guide/expression#-event- Event object is available as `$event`})
34013  *
34014  * @example
34015    <example module="submitExample">
34016      <file name="index.html">
34017       <script>
34018         angular.module('submitExample', [])
34019           .controller('ExampleController', ['$scope', function($scope) {
34020             $scope.list = [];
34021             $scope.text = 'hello';
34022             $scope.submit = function() {
34023               if ($scope.text) {
34024                 $scope.list.push(this.text);
34025                 $scope.text = '';
34026               }
34027             };
34028           }]);
34029       </script>
34030       <form ng-submit="submit()" ng-controller="ExampleController">
34031         Enter text and hit enter:
34032         <input type="text" ng-model="text" name="text" />
34033         <input type="submit" id="submit" value="Submit" />
34034         <pre>list={{list}}</pre>
34035       </form>
34036      </file>
34037      <file name="protractor.js" type="protractor">
34038        it('should check ng-submit', function() {
34039          expect(element(by.binding('list')).getText()).toBe('list=[]');
34040          element(by.css('#submit')).click();
34041          expect(element(by.binding('list')).getText()).toContain('hello');
34042          expect(element(by.model('text')).getAttribute('value')).toBe('');
34043        });
34044        it('should ignore empty strings', function() {
34045          expect(element(by.binding('list')).getText()).toBe('list=[]');
34046          element(by.css('#submit')).click();
34047          element(by.css('#submit')).click();
34048          expect(element(by.binding('list')).getText()).toContain('hello');
34049         });
34050      </file>
34051    </example>
34052  */
34053
34054 /**
34055  * @ngdoc directive
34056  * @name ngFocus
34057  *
34058  * @description
34059  * Specify custom behavior on focus event.
34060  *
34061  * Note: As the `focus` event is executed synchronously when calling `input.focus()`
34062  * AngularJS executes the expression using `scope.$evalAsync` if the event is fired
34063  * during an `$apply` to ensure a consistent state.
34064  *
34065  * @element window, input, select, textarea, a
34066  * @priority 0
34067  * @param {expression} ngFocus {@link guide/expression Expression} to evaluate upon
34068  * focus. ({@link guide/expression#-event- Event object is available as `$event`})
34069  *
34070  * @example
34071  * See {@link ng.directive:ngClick ngClick}
34072  */
34073
34074 /**
34075  * @ngdoc directive
34076  * @name ngBlur
34077  *
34078  * @description
34079  * Specify custom behavior on blur event.
34080  *
34081  * A [blur event](https://developer.mozilla.org/en-US/docs/Web/Events/blur) fires when
34082  * an element has lost focus.
34083  *
34084  * Note: As the `blur` event is executed synchronously also during DOM manipulations
34085  * (e.g. removing a focussed input),
34086  * AngularJS executes the expression using `scope.$evalAsync` if the event is fired
34087  * during an `$apply` to ensure a consistent state.
34088  *
34089  * @element window, input, select, textarea, a
34090  * @priority 0
34091  * @param {expression} ngBlur {@link guide/expression Expression} to evaluate upon
34092  * blur. ({@link guide/expression#-event- Event object is available as `$event`})
34093  *
34094  * @example
34095  * See {@link ng.directive:ngClick ngClick}
34096  */
34097
34098 /**
34099  * @ngdoc directive
34100  * @name ngCopy
34101  *
34102  * @description
34103  * Specify custom behavior on copy event.
34104  *
34105  * @element window, input, select, textarea, a
34106  * @priority 0
34107  * @param {expression} ngCopy {@link guide/expression Expression} to evaluate upon
34108  * copy. ({@link guide/expression#-event- Event object is available as `$event`})
34109  *
34110  * @example
34111    <example>
34112      <file name="index.html">
34113       <input ng-copy="copied=true" ng-init="copied=false; value='copy me'" ng-model="value">
34114       copied: {{copied}}
34115      </file>
34116    </example>
34117  */
34118
34119 /**
34120  * @ngdoc directive
34121  * @name ngCut
34122  *
34123  * @description
34124  * Specify custom behavior on cut event.
34125  *
34126  * @element window, input, select, textarea, a
34127  * @priority 0
34128  * @param {expression} ngCut {@link guide/expression Expression} to evaluate upon
34129  * cut. ({@link guide/expression#-event- Event object is available as `$event`})
34130  *
34131  * @example
34132    <example>
34133      <file name="index.html">
34134       <input ng-cut="cut=true" ng-init="cut=false; value='cut me'" ng-model="value">
34135       cut: {{cut}}
34136      </file>
34137    </example>
34138  */
34139
34140 /**
34141  * @ngdoc directive
34142  * @name ngPaste
34143  *
34144  * @description
34145  * Specify custom behavior on paste event.
34146  *
34147  * @element window, input, select, textarea, a
34148  * @priority 0
34149  * @param {expression} ngPaste {@link guide/expression Expression} to evaluate upon
34150  * paste. ({@link guide/expression#-event- Event object is available as `$event`})
34151  *
34152  * @example
34153    <example>
34154      <file name="index.html">
34155       <input ng-paste="paste=true" ng-init="paste=false" placeholder='paste here'>
34156       pasted: {{paste}}
34157      </file>
34158    </example>
34159  */
34160
34161 /**
34162  * @ngdoc directive
34163  * @name ngIf
34164  * @restrict A
34165  * @multiElement
34166  *
34167  * @description
34168  * The `ngIf` directive removes or recreates a portion of the DOM tree based on an
34169  * {expression}. If the expression assigned to `ngIf` evaluates to a false
34170  * value then the element is removed from the DOM, otherwise a clone of the
34171  * element is reinserted into the DOM.
34172  *
34173  * `ngIf` differs from `ngShow` and `ngHide` in that `ngIf` completely removes and recreates the
34174  * element in the DOM rather than changing its visibility via the `display` css property.  A common
34175  * case when this difference is significant is when using css selectors that rely on an element's
34176  * position within the DOM, such as the `:first-child` or `:last-child` pseudo-classes.
34177  *
34178  * Note that when an element is removed using `ngIf` its scope is destroyed and a new scope
34179  * is created when the element is restored.  The scope created within `ngIf` inherits from
34180  * its parent scope using
34181  * [prototypal inheritance](https://github.com/angular/angular.js/wiki/Understanding-Scopes#javascript-prototypal-inheritance).
34182  * An important implication of this is if `ngModel` is used within `ngIf` to bind to
34183  * a javascript primitive defined in the parent scope. In this case any modifications made to the
34184  * variable within the child scope will override (hide) the value in the parent scope.
34185  *
34186  * Also, `ngIf` recreates elements using their compiled state. An example of this behavior
34187  * is if an element's class attribute is directly modified after it's compiled, using something like
34188  * jQuery's `.addClass()` method, and the element is later removed. When `ngIf` recreates the element
34189  * the added class will be lost because the original compiled state is used to regenerate the element.
34190  *
34191  * Additionally, you can provide animations via the `ngAnimate` module to animate the `enter`
34192  * and `leave` effects.
34193  *
34194  * @animations
34195  * enter - happens just after the `ngIf` contents change and a new DOM element is created and injected into the `ngIf` container
34196  * leave - happens just before the `ngIf` contents are removed from the DOM
34197  *
34198  * @element ANY
34199  * @scope
34200  * @priority 600
34201  * @param {expression} ngIf If the {@link guide/expression expression} is falsy then
34202  *     the element is removed from the DOM tree. If it is truthy a copy of the compiled
34203  *     element is added to the DOM tree.
34204  *
34205  * @example
34206   <example module="ngAnimate" deps="angular-animate.js" animations="true">
34207     <file name="index.html">
34208       <label>Click me: <input type="checkbox" ng-model="checked" ng-init="checked=true" /></label><br/>
34209       Show when checked:
34210       <span ng-if="checked" class="animate-if">
34211         This is removed when the checkbox is unchecked.
34212       </span>
34213     </file>
34214     <file name="animations.css">
34215       .animate-if {
34216         background:white;
34217         border:1px solid black;
34218         padding:10px;
34219       }
34220
34221       .animate-if.ng-enter, .animate-if.ng-leave {
34222         transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
34223       }
34224
34225       .animate-if.ng-enter,
34226       .animate-if.ng-leave.ng-leave-active {
34227         opacity:0;
34228       }
34229
34230       .animate-if.ng-leave,
34231       .animate-if.ng-enter.ng-enter-active {
34232         opacity:1;
34233       }
34234     </file>
34235   </example>
34236  */
34237 var ngIfDirective = ['$animate', function($animate) {
34238   return {
34239     multiElement: true,
34240     transclude: 'element',
34241     priority: 600,
34242     terminal: true,
34243     restrict: 'A',
34244     $$tlb: true,
34245     link: function($scope, $element, $attr, ctrl, $transclude) {
34246         var block, childScope, previousElements;
34247         $scope.$watch($attr.ngIf, function ngIfWatchAction(value) {
34248
34249           if (value) {
34250             if (!childScope) {
34251               $transclude(function(clone, newScope) {
34252                 childScope = newScope;
34253                 clone[clone.length++] = document.createComment(' end ngIf: ' + $attr.ngIf + ' ');
34254                 // Note: We only need the first/last node of the cloned nodes.
34255                 // However, we need to keep the reference to the jqlite wrapper as it might be changed later
34256                 // by a directive with templateUrl when its template arrives.
34257                 block = {
34258                   clone: clone
34259                 };
34260                 $animate.enter(clone, $element.parent(), $element);
34261               });
34262             }
34263           } else {
34264             if (previousElements) {
34265               previousElements.remove();
34266               previousElements = null;
34267             }
34268             if (childScope) {
34269               childScope.$destroy();
34270               childScope = null;
34271             }
34272             if (block) {
34273               previousElements = getBlockNodes(block.clone);
34274               $animate.leave(previousElements).then(function() {
34275                 previousElements = null;
34276               });
34277               block = null;
34278             }
34279           }
34280         });
34281     }
34282   };
34283 }];
34284
34285 /**
34286  * @ngdoc directive
34287  * @name ngInclude
34288  * @restrict ECA
34289  *
34290  * @description
34291  * Fetches, compiles and includes an external HTML fragment.
34292  *
34293  * By default, the template URL is restricted to the same domain and protocol as the
34294  * application document. This is done by calling {@link $sce#getTrustedResourceUrl
34295  * $sce.getTrustedResourceUrl} on it. To load templates from other domains or protocols
34296  * you may either {@link ng.$sceDelegateProvider#resourceUrlWhitelist whitelist them} or
34297  * {@link $sce#trustAsResourceUrl wrap them} as trusted values. Refer to Angular's {@link
34298  * ng.$sce Strict Contextual Escaping}.
34299  *
34300  * In addition, the browser's
34301  * [Same Origin Policy](https://code.google.com/p/browsersec/wiki/Part2#Same-origin_policy_for_XMLHttpRequest)
34302  * and [Cross-Origin Resource Sharing (CORS)](http://www.w3.org/TR/cors/)
34303  * policy may further restrict whether the template is successfully loaded.
34304  * For example, `ngInclude` won't work for cross-domain requests on all browsers and for `file://`
34305  * access on some browsers.
34306  *
34307  * @animations
34308  * enter - animation is used to bring new content into the browser.
34309  * leave - animation is used to animate existing content away.
34310  *
34311  * The enter and leave animation occur concurrently.
34312  *
34313  * @scope
34314  * @priority 400
34315  *
34316  * @param {string} ngInclude|src angular expression evaluating to URL. If the source is a string constant,
34317  *                 make sure you wrap it in **single** quotes, e.g. `src="'myPartialTemplate.html'"`.
34318  * @param {string=} onload Expression to evaluate when a new partial is loaded.
34319  *                  <div class="alert alert-warning">
34320  *                  **Note:** When using onload on SVG elements in IE11, the browser will try to call
34321  *                  a function with the name on the window element, which will usually throw a
34322  *                  "function is undefined" error. To fix this, you can instead use `data-onload` or a
34323  *                  different form that {@link guide/directive#normalization matches} `onload`.
34324  *                  </div>
34325    *
34326  * @param {string=} autoscroll Whether `ngInclude` should call {@link ng.$anchorScroll
34327  *                  $anchorScroll} to scroll the viewport after the content is loaded.
34328  *
34329  *                  - If the attribute is not set, disable scrolling.
34330  *                  - If the attribute is set without value, enable scrolling.
34331  *                  - Otherwise enable scrolling only if the expression evaluates to truthy value.
34332  *
34333  * @example
34334   <example module="includeExample" deps="angular-animate.js" animations="true">
34335     <file name="index.html">
34336      <div ng-controller="ExampleController">
34337        <select ng-model="template" ng-options="t.name for t in templates">
34338         <option value="">(blank)</option>
34339        </select>
34340        url of the template: <code>{{template.url}}</code>
34341        <hr/>
34342        <div class="slide-animate-container">
34343          <div class="slide-animate" ng-include="template.url"></div>
34344        </div>
34345      </div>
34346     </file>
34347     <file name="script.js">
34348       angular.module('includeExample', ['ngAnimate'])
34349         .controller('ExampleController', ['$scope', function($scope) {
34350           $scope.templates =
34351             [ { name: 'template1.html', url: 'template1.html'},
34352               { name: 'template2.html', url: 'template2.html'} ];
34353           $scope.template = $scope.templates[0];
34354         }]);
34355      </file>
34356     <file name="template1.html">
34357       Content of template1.html
34358     </file>
34359     <file name="template2.html">
34360       Content of template2.html
34361     </file>
34362     <file name="animations.css">
34363       .slide-animate-container {
34364         position:relative;
34365         background:white;
34366         border:1px solid black;
34367         height:40px;
34368         overflow:hidden;
34369       }
34370
34371       .slide-animate {
34372         padding:10px;
34373       }
34374
34375       .slide-animate.ng-enter, .slide-animate.ng-leave {
34376         transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
34377
34378         position:absolute;
34379         top:0;
34380         left:0;
34381         right:0;
34382         bottom:0;
34383         display:block;
34384         padding:10px;
34385       }
34386
34387       .slide-animate.ng-enter {
34388         top:-50px;
34389       }
34390       .slide-animate.ng-enter.ng-enter-active {
34391         top:0;
34392       }
34393
34394       .slide-animate.ng-leave {
34395         top:0;
34396       }
34397       .slide-animate.ng-leave.ng-leave-active {
34398         top:50px;
34399       }
34400     </file>
34401     <file name="protractor.js" type="protractor">
34402       var templateSelect = element(by.model('template'));
34403       var includeElem = element(by.css('[ng-include]'));
34404
34405       it('should load template1.html', function() {
34406         expect(includeElem.getText()).toMatch(/Content of template1.html/);
34407       });
34408
34409       it('should load template2.html', function() {
34410         if (browser.params.browser == 'firefox') {
34411           // Firefox can't handle using selects
34412           // See https://github.com/angular/protractor/issues/480
34413           return;
34414         }
34415         templateSelect.click();
34416         templateSelect.all(by.css('option')).get(2).click();
34417         expect(includeElem.getText()).toMatch(/Content of template2.html/);
34418       });
34419
34420       it('should change to blank', function() {
34421         if (browser.params.browser == 'firefox') {
34422           // Firefox can't handle using selects
34423           return;
34424         }
34425         templateSelect.click();
34426         templateSelect.all(by.css('option')).get(0).click();
34427         expect(includeElem.isPresent()).toBe(false);
34428       });
34429     </file>
34430   </example>
34431  */
34432
34433
34434 /**
34435  * @ngdoc event
34436  * @name ngInclude#$includeContentRequested
34437  * @eventType emit on the scope ngInclude was declared in
34438  * @description
34439  * Emitted every time the ngInclude content is requested.
34440  *
34441  * @param {Object} angularEvent Synthetic event object.
34442  * @param {String} src URL of content to load.
34443  */
34444
34445
34446 /**
34447  * @ngdoc event
34448  * @name ngInclude#$includeContentLoaded
34449  * @eventType emit on the current ngInclude scope
34450  * @description
34451  * Emitted every time the ngInclude content is reloaded.
34452  *
34453  * @param {Object} angularEvent Synthetic event object.
34454  * @param {String} src URL of content to load.
34455  */
34456
34457
34458 /**
34459  * @ngdoc event
34460  * @name ngInclude#$includeContentError
34461  * @eventType emit on the scope ngInclude was declared in
34462  * @description
34463  * Emitted when a template HTTP request yields an erroneous response (status < 200 || status > 299)
34464  *
34465  * @param {Object} angularEvent Synthetic event object.
34466  * @param {String} src URL of content to load.
34467  */
34468 var ngIncludeDirective = ['$templateRequest', '$anchorScroll', '$animate',
34469                   function($templateRequest,   $anchorScroll,   $animate) {
34470   return {
34471     restrict: 'ECA',
34472     priority: 400,
34473     terminal: true,
34474     transclude: 'element',
34475     controller: angular.noop,
34476     compile: function(element, attr) {
34477       var srcExp = attr.ngInclude || attr.src,
34478           onloadExp = attr.onload || '',
34479           autoScrollExp = attr.autoscroll;
34480
34481       return function(scope, $element, $attr, ctrl, $transclude) {
34482         var changeCounter = 0,
34483             currentScope,
34484             previousElement,
34485             currentElement;
34486
34487         var cleanupLastIncludeContent = function() {
34488           if (previousElement) {
34489             previousElement.remove();
34490             previousElement = null;
34491           }
34492           if (currentScope) {
34493             currentScope.$destroy();
34494             currentScope = null;
34495           }
34496           if (currentElement) {
34497             $animate.leave(currentElement).then(function() {
34498               previousElement = null;
34499             });
34500             previousElement = currentElement;
34501             currentElement = null;
34502           }
34503         };
34504
34505         scope.$watch(srcExp, function ngIncludeWatchAction(src) {
34506           var afterAnimation = function() {
34507             if (isDefined(autoScrollExp) && (!autoScrollExp || scope.$eval(autoScrollExp))) {
34508               $anchorScroll();
34509             }
34510           };
34511           var thisChangeId = ++changeCounter;
34512
34513           if (src) {
34514             //set the 2nd param to true to ignore the template request error so that the inner
34515             //contents and scope can be cleaned up.
34516             $templateRequest(src, true).then(function(response) {
34517               if (scope.$$destroyed) return;
34518
34519               if (thisChangeId !== changeCounter) return;
34520               var newScope = scope.$new();
34521               ctrl.template = response;
34522
34523               // Note: This will also link all children of ng-include that were contained in the original
34524               // html. If that content contains controllers, ... they could pollute/change the scope.
34525               // However, using ng-include on an element with additional content does not make sense...
34526               // Note: We can't remove them in the cloneAttchFn of $transclude as that
34527               // function is called before linking the content, which would apply child
34528               // directives to non existing elements.
34529               var clone = $transclude(newScope, function(clone) {
34530                 cleanupLastIncludeContent();
34531                 $animate.enter(clone, null, $element).then(afterAnimation);
34532               });
34533
34534               currentScope = newScope;
34535               currentElement = clone;
34536
34537               currentScope.$emit('$includeContentLoaded', src);
34538               scope.$eval(onloadExp);
34539             }, function() {
34540               if (scope.$$destroyed) return;
34541
34542               if (thisChangeId === changeCounter) {
34543                 cleanupLastIncludeContent();
34544                 scope.$emit('$includeContentError', src);
34545               }
34546             });
34547             scope.$emit('$includeContentRequested', src);
34548           } else {
34549             cleanupLastIncludeContent();
34550             ctrl.template = null;
34551           }
34552         });
34553       };
34554     }
34555   };
34556 }];
34557
34558 // This directive is called during the $transclude call of the first `ngInclude` directive.
34559 // It will replace and compile the content of the element with the loaded template.
34560 // We need this directive so that the element content is already filled when
34561 // the link function of another directive on the same element as ngInclude
34562 // is called.
34563 var ngIncludeFillContentDirective = ['$compile',
34564   function($compile) {
34565     return {
34566       restrict: 'ECA',
34567       priority: -400,
34568       require: 'ngInclude',
34569       link: function(scope, $element, $attr, ctrl) {
34570         if (toString.call($element[0]).match(/SVG/)) {
34571           // WebKit: https://bugs.webkit.org/show_bug.cgi?id=135698 --- SVG elements do not
34572           // support innerHTML, so detect this here and try to generate the contents
34573           // specially.
34574           $element.empty();
34575           $compile(jqLiteBuildFragment(ctrl.template, document).childNodes)(scope,
34576               function namespaceAdaptedClone(clone) {
34577             $element.append(clone);
34578           }, {futureParentElement: $element});
34579           return;
34580         }
34581
34582         $element.html(ctrl.template);
34583         $compile($element.contents())(scope);
34584       }
34585     };
34586   }];
34587
34588 /**
34589  * @ngdoc directive
34590  * @name ngInit
34591  * @restrict AC
34592  *
34593  * @description
34594  * The `ngInit` directive allows you to evaluate an expression in the
34595  * current scope.
34596  *
34597  * <div class="alert alert-danger">
34598  * This directive can be abused to add unnecessary amounts of logic into your templates.
34599  * There are only a few appropriate uses of `ngInit`, such as for aliasing special properties of
34600  * {@link ng.directive:ngRepeat `ngRepeat`}, as seen in the demo below; and for injecting data via
34601  * server side scripting. Besides these few cases, you should use {@link guide/controller controllers}
34602  * rather than `ngInit` to initialize values on a scope.
34603  * </div>
34604  *
34605  * <div class="alert alert-warning">
34606  * **Note**: If you have assignment in `ngInit` along with a {@link ng.$filter `filter`}, make
34607  * sure you have parentheses to ensure correct operator precedence:
34608  * <pre class="prettyprint">
34609  * `<div ng-init="test1 = ($index | toString)"></div>`
34610  * </pre>
34611  * </div>
34612  *
34613  * @priority 450
34614  *
34615  * @element ANY
34616  * @param {expression} ngInit {@link guide/expression Expression} to eval.
34617  *
34618  * @example
34619    <example module="initExample">
34620      <file name="index.html">
34621    <script>
34622      angular.module('initExample', [])
34623        .controller('ExampleController', ['$scope', function($scope) {
34624          $scope.list = [['a', 'b'], ['c', 'd']];
34625        }]);
34626    </script>
34627    <div ng-controller="ExampleController">
34628      <div ng-repeat="innerList in list" ng-init="outerIndex = $index">
34629        <div ng-repeat="value in innerList" ng-init="innerIndex = $index">
34630           <span class="example-init">list[ {{outerIndex}} ][ {{innerIndex}} ] = {{value}};</span>
34631        </div>
34632      </div>
34633    </div>
34634      </file>
34635      <file name="protractor.js" type="protractor">
34636        it('should alias index positions', function() {
34637          var elements = element.all(by.css('.example-init'));
34638          expect(elements.get(0).getText()).toBe('list[ 0 ][ 0 ] = a;');
34639          expect(elements.get(1).getText()).toBe('list[ 0 ][ 1 ] = b;');
34640          expect(elements.get(2).getText()).toBe('list[ 1 ][ 0 ] = c;');
34641          expect(elements.get(3).getText()).toBe('list[ 1 ][ 1 ] = d;');
34642        });
34643      </file>
34644    </example>
34645  */
34646 var ngInitDirective = ngDirective({
34647   priority: 450,
34648   compile: function() {
34649     return {
34650       pre: function(scope, element, attrs) {
34651         scope.$eval(attrs.ngInit);
34652       }
34653     };
34654   }
34655 });
34656
34657 /**
34658  * @ngdoc directive
34659  * @name ngList
34660  *
34661  * @description
34662  * Text input that converts between a delimited string and an array of strings. The default
34663  * delimiter is a comma followed by a space - equivalent to `ng-list=", "`. You can specify a custom
34664  * delimiter as the value of the `ngList` attribute - for example, `ng-list=" | "`.
34665  *
34666  * The behaviour of the directive is affected by the use of the `ngTrim` attribute.
34667  * * If `ngTrim` is set to `"false"` then whitespace around both the separator and each
34668  *   list item is respected. This implies that the user of the directive is responsible for
34669  *   dealing with whitespace but also allows you to use whitespace as a delimiter, such as a
34670  *   tab or newline character.
34671  * * Otherwise whitespace around the delimiter is ignored when splitting (although it is respected
34672  *   when joining the list items back together) and whitespace around each list item is stripped
34673  *   before it is added to the model.
34674  *
34675  * ### Example with Validation
34676  *
34677  * <example name="ngList-directive" module="listExample">
34678  *   <file name="app.js">
34679  *      angular.module('listExample', [])
34680  *        .controller('ExampleController', ['$scope', function($scope) {
34681  *          $scope.names = ['morpheus', 'neo', 'trinity'];
34682  *        }]);
34683  *   </file>
34684  *   <file name="index.html">
34685  *    <form name="myForm" ng-controller="ExampleController">
34686  *      <label>List: <input name="namesInput" ng-model="names" ng-list required></label>
34687  *      <span role="alert">
34688  *        <span class="error" ng-show="myForm.namesInput.$error.required">
34689  *        Required!</span>
34690  *      </span>
34691  *      <br>
34692  *      <tt>names = {{names}}</tt><br/>
34693  *      <tt>myForm.namesInput.$valid = {{myForm.namesInput.$valid}}</tt><br/>
34694  *      <tt>myForm.namesInput.$error = {{myForm.namesInput.$error}}</tt><br/>
34695  *      <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
34696  *      <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
34697  *     </form>
34698  *   </file>
34699  *   <file name="protractor.js" type="protractor">
34700  *     var listInput = element(by.model('names'));
34701  *     var names = element(by.exactBinding('names'));
34702  *     var valid = element(by.binding('myForm.namesInput.$valid'));
34703  *     var error = element(by.css('span.error'));
34704  *
34705  *     it('should initialize to model', function() {
34706  *       expect(names.getText()).toContain('["morpheus","neo","trinity"]');
34707  *       expect(valid.getText()).toContain('true');
34708  *       expect(error.getCssValue('display')).toBe('none');
34709  *     });
34710  *
34711  *     it('should be invalid if empty', function() {
34712  *       listInput.clear();
34713  *       listInput.sendKeys('');
34714  *
34715  *       expect(names.getText()).toContain('');
34716  *       expect(valid.getText()).toContain('false');
34717  *       expect(error.getCssValue('display')).not.toBe('none');
34718  *     });
34719  *   </file>
34720  * </example>
34721  *
34722  * ### Example - splitting on newline
34723  * <example name="ngList-directive-newlines">
34724  *   <file name="index.html">
34725  *    <textarea ng-model="list" ng-list="&#10;" ng-trim="false"></textarea>
34726  *    <pre>{{ list | json }}</pre>
34727  *   </file>
34728  *   <file name="protractor.js" type="protractor">
34729  *     it("should split the text by newlines", function() {
34730  *       var listInput = element(by.model('list'));
34731  *       var output = element(by.binding('list | json'));
34732  *       listInput.sendKeys('abc\ndef\nghi');
34733  *       expect(output.getText()).toContain('[\n  "abc",\n  "def",\n  "ghi"\n]');
34734  *     });
34735  *   </file>
34736  * </example>
34737  *
34738  * @element input
34739  * @param {string=} ngList optional delimiter that should be used to split the value.
34740  */
34741 var ngListDirective = function() {
34742   return {
34743     restrict: 'A',
34744     priority: 100,
34745     require: 'ngModel',
34746     link: function(scope, element, attr, ctrl) {
34747       // We want to control whitespace trimming so we use this convoluted approach
34748       // to access the ngList attribute, which doesn't pre-trim the attribute
34749       var ngList = element.attr(attr.$attr.ngList) || ', ';
34750       var trimValues = attr.ngTrim !== 'false';
34751       var separator = trimValues ? trim(ngList) : ngList;
34752
34753       var parse = function(viewValue) {
34754         // If the viewValue is invalid (say required but empty) it will be `undefined`
34755         if (isUndefined(viewValue)) return;
34756
34757         var list = [];
34758
34759         if (viewValue) {
34760           forEach(viewValue.split(separator), function(value) {
34761             if (value) list.push(trimValues ? trim(value) : value);
34762           });
34763         }
34764
34765         return list;
34766       };
34767
34768       ctrl.$parsers.push(parse);
34769       ctrl.$formatters.push(function(value) {
34770         if (isArray(value)) {
34771           return value.join(ngList);
34772         }
34773
34774         return undefined;
34775       });
34776
34777       // Override the standard $isEmpty because an empty array means the input is empty.
34778       ctrl.$isEmpty = function(value) {
34779         return !value || !value.length;
34780       };
34781     }
34782   };
34783 };
34784
34785 /* global VALID_CLASS: true,
34786   INVALID_CLASS: true,
34787   PRISTINE_CLASS: true,
34788   DIRTY_CLASS: true,
34789   UNTOUCHED_CLASS: true,
34790   TOUCHED_CLASS: true,
34791 */
34792
34793 var VALID_CLASS = 'ng-valid',
34794     INVALID_CLASS = 'ng-invalid',
34795     PRISTINE_CLASS = 'ng-pristine',
34796     DIRTY_CLASS = 'ng-dirty',
34797     UNTOUCHED_CLASS = 'ng-untouched',
34798     TOUCHED_CLASS = 'ng-touched',
34799     PENDING_CLASS = 'ng-pending',
34800     EMPTY_CLASS = 'ng-empty',
34801     NOT_EMPTY_CLASS = 'ng-not-empty';
34802
34803 var ngModelMinErr = minErr('ngModel');
34804
34805 /**
34806  * @ngdoc type
34807  * @name ngModel.NgModelController
34808  *
34809  * @property {*} $viewValue The actual value from the control's view. For `input` elements, this is a
34810  * String. See {@link ngModel.NgModelController#$setViewValue} for information about when the $viewValue
34811  * is set.
34812  * @property {*} $modelValue The value in the model that the control is bound to.
34813  * @property {Array.<Function>} $parsers Array of functions to execute, as a pipeline, whenever
34814        the control reads value from the DOM. The functions are called in array order, each passing
34815        its return value through to the next. The last return value is forwarded to the
34816        {@link ngModel.NgModelController#$validators `$validators`} collection.
34817
34818 Parsers are used to sanitize / convert the {@link ngModel.NgModelController#$viewValue
34819 `$viewValue`}.
34820
34821 Returning `undefined` from a parser means a parse error occurred. In that case,
34822 no {@link ngModel.NgModelController#$validators `$validators`} will run and the `ngModel`
34823 will be set to `undefined` unless {@link ngModelOptions `ngModelOptions.allowInvalid`}
34824 is set to `true`. The parse error is stored in `ngModel.$error.parse`.
34825
34826  *
34827  * @property {Array.<Function>} $formatters Array of functions to execute, as a pipeline, whenever
34828        the model value changes. The functions are called in reverse array order, each passing the value through to the
34829        next. The last return value is used as the actual DOM value.
34830        Used to format / convert values for display in the control.
34831  * ```js
34832  * function formatter(value) {
34833  *   if (value) {
34834  *     return value.toUpperCase();
34835  *   }
34836  * }
34837  * ngModel.$formatters.push(formatter);
34838  * ```
34839  *
34840  * @property {Object.<string, function>} $validators A collection of validators that are applied
34841  *      whenever the model value changes. The key value within the object refers to the name of the
34842  *      validator while the function refers to the validation operation. The validation operation is
34843  *      provided with the model value as an argument and must return a true or false value depending
34844  *      on the response of that validation.
34845  *
34846  * ```js
34847  * ngModel.$validators.validCharacters = function(modelValue, viewValue) {
34848  *   var value = modelValue || viewValue;
34849  *   return /[0-9]+/.test(value) &&
34850  *          /[a-z]+/.test(value) &&
34851  *          /[A-Z]+/.test(value) &&
34852  *          /\W+/.test(value);
34853  * };
34854  * ```
34855  *
34856  * @property {Object.<string, function>} $asyncValidators A collection of validations that are expected to
34857  *      perform an asynchronous validation (e.g. a HTTP request). The validation function that is provided
34858  *      is expected to return a promise when it is run during the model validation process. Once the promise
34859  *      is delivered then the validation status will be set to true when fulfilled and false when rejected.
34860  *      When the asynchronous validators are triggered, each of the validators will run in parallel and the model
34861  *      value will only be updated once all validators have been fulfilled. As long as an asynchronous validator
34862  *      is unfulfilled, its key will be added to the controllers `$pending` property. Also, all asynchronous validators
34863  *      will only run once all synchronous validators have passed.
34864  *
34865  * Please note that if $http is used then it is important that the server returns a success HTTP response code
34866  * in order to fulfill the validation and a status level of `4xx` in order to reject the validation.
34867  *
34868  * ```js
34869  * ngModel.$asyncValidators.uniqueUsername = function(modelValue, viewValue) {
34870  *   var value = modelValue || viewValue;
34871  *
34872  *   // Lookup user by username
34873  *   return $http.get('/api/users/' + value).
34874  *      then(function resolved() {
34875  *        //username exists, this means validation fails
34876  *        return $q.reject('exists');
34877  *      }, function rejected() {
34878  *        //username does not exist, therefore this validation passes
34879  *        return true;
34880  *      });
34881  * };
34882  * ```
34883  *
34884  * @property {Array.<Function>} $viewChangeListeners Array of functions to execute whenever the
34885  *     view value has changed. It is called with no arguments, and its return value is ignored.
34886  *     This can be used in place of additional $watches against the model value.
34887  *
34888  * @property {Object} $error An object hash with all failing validator ids as keys.
34889  * @property {Object} $pending An object hash with all pending validator ids as keys.
34890  *
34891  * @property {boolean} $untouched True if control has not lost focus yet.
34892  * @property {boolean} $touched True if control has lost focus.
34893  * @property {boolean} $pristine True if user has not interacted with the control yet.
34894  * @property {boolean} $dirty True if user has already interacted with the control.
34895  * @property {boolean} $valid True if there is no error.
34896  * @property {boolean} $invalid True if at least one error on the control.
34897  * @property {string} $name The name attribute of the control.
34898  *
34899  * @description
34900  *
34901  * `NgModelController` provides API for the {@link ngModel `ngModel`} directive.
34902  * The controller contains services for data-binding, validation, CSS updates, and value formatting
34903  * and parsing. It purposefully does not contain any logic which deals with DOM rendering or
34904  * listening to DOM events.
34905  * Such DOM related logic should be provided by other directives which make use of
34906  * `NgModelController` for data-binding to control elements.
34907  * Angular provides this DOM logic for most {@link input `input`} elements.
34908  * At the end of this page you can find a {@link ngModel.NgModelController#custom-control-example
34909  * custom control example} that uses `ngModelController` to bind to `contenteditable` elements.
34910  *
34911  * @example
34912  * ### Custom Control Example
34913  * This example shows how to use `NgModelController` with a custom control to achieve
34914  * data-binding. Notice how different directives (`contenteditable`, `ng-model`, and `required`)
34915  * collaborate together to achieve the desired result.
34916  *
34917  * `contenteditable` is an HTML5 attribute, which tells the browser to let the element
34918  * contents be edited in place by the user.
34919  *
34920  * We are using the {@link ng.service:$sce $sce} service here and include the {@link ngSanitize $sanitize}
34921  * module to automatically remove "bad" content like inline event listener (e.g. `<span onclick="...">`).
34922  * However, as we are using `$sce` the model can still decide to provide unsafe content if it marks
34923  * that content using the `$sce` service.
34924  *
34925  * <example name="NgModelController" module="customControl" deps="angular-sanitize.js">
34926     <file name="style.css">
34927       [contenteditable] {
34928         border: 1px solid black;
34929         background-color: white;
34930         min-height: 20px;
34931       }
34932
34933       .ng-invalid {
34934         border: 1px solid red;
34935       }
34936
34937     </file>
34938     <file name="script.js">
34939       angular.module('customControl', ['ngSanitize']).
34940         directive('contenteditable', ['$sce', function($sce) {
34941           return {
34942             restrict: 'A', // only activate on element attribute
34943             require: '?ngModel', // get a hold of NgModelController
34944             link: function(scope, element, attrs, ngModel) {
34945               if (!ngModel) return; // do nothing if no ng-model
34946
34947               // Specify how UI should be updated
34948               ngModel.$render = function() {
34949                 element.html($sce.getTrustedHtml(ngModel.$viewValue || ''));
34950               };
34951
34952               // Listen for change events to enable binding
34953               element.on('blur keyup change', function() {
34954                 scope.$evalAsync(read);
34955               });
34956               read(); // initialize
34957
34958               // Write data to the model
34959               function read() {
34960                 var html = element.html();
34961                 // When we clear the content editable the browser leaves a <br> behind
34962                 // If strip-br attribute is provided then we strip this out
34963                 if ( attrs.stripBr && html == '<br>' ) {
34964                   html = '';
34965                 }
34966                 ngModel.$setViewValue(html);
34967               }
34968             }
34969           };
34970         }]);
34971     </file>
34972     <file name="index.html">
34973       <form name="myForm">
34974        <div contenteditable
34975             name="myWidget" ng-model="userContent"
34976             strip-br="true"
34977             required>Change me!</div>
34978         <span ng-show="myForm.myWidget.$error.required">Required!</span>
34979        <hr>
34980        <textarea ng-model="userContent" aria-label="Dynamic textarea"></textarea>
34981       </form>
34982     </file>
34983     <file name="protractor.js" type="protractor">
34984     it('should data-bind and become invalid', function() {
34985       if (browser.params.browser == 'safari' || browser.params.browser == 'firefox') {
34986         // SafariDriver can't handle contenteditable
34987         // and Firefox driver can't clear contenteditables very well
34988         return;
34989       }
34990       var contentEditable = element(by.css('[contenteditable]'));
34991       var content = 'Change me!';
34992
34993       expect(contentEditable.getText()).toEqual(content);
34994
34995       contentEditable.clear();
34996       contentEditable.sendKeys(protractor.Key.BACK_SPACE);
34997       expect(contentEditable.getText()).toEqual('');
34998       expect(contentEditable.getAttribute('class')).toMatch(/ng-invalid-required/);
34999     });
35000     </file>
35001  * </example>
35002  *
35003  *
35004  */
35005 var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$parse', '$animate', '$timeout', '$rootScope', '$q', '$interpolate',
35006     function($scope, $exceptionHandler, $attr, $element, $parse, $animate, $timeout, $rootScope, $q, $interpolate) {
35007   this.$viewValue = Number.NaN;
35008   this.$modelValue = Number.NaN;
35009   this.$$rawModelValue = undefined; // stores the parsed modelValue / model set from scope regardless of validity.
35010   this.$validators = {};
35011   this.$asyncValidators = {};
35012   this.$parsers = [];
35013   this.$formatters = [];
35014   this.$viewChangeListeners = [];
35015   this.$untouched = true;
35016   this.$touched = false;
35017   this.$pristine = true;
35018   this.$dirty = false;
35019   this.$valid = true;
35020   this.$invalid = false;
35021   this.$error = {}; // keep invalid keys here
35022   this.$$success = {}; // keep valid keys here
35023   this.$pending = undefined; // keep pending keys here
35024   this.$name = $interpolate($attr.name || '', false)($scope);
35025   this.$$parentForm = nullFormCtrl;
35026
35027   var parsedNgModel = $parse($attr.ngModel),
35028       parsedNgModelAssign = parsedNgModel.assign,
35029       ngModelGet = parsedNgModel,
35030       ngModelSet = parsedNgModelAssign,
35031       pendingDebounce = null,
35032       parserValid,
35033       ctrl = this;
35034
35035   this.$$setOptions = function(options) {
35036     ctrl.$options = options;
35037     if (options && options.getterSetter) {
35038       var invokeModelGetter = $parse($attr.ngModel + '()'),
35039           invokeModelSetter = $parse($attr.ngModel + '($$$p)');
35040
35041       ngModelGet = function($scope) {
35042         var modelValue = parsedNgModel($scope);
35043         if (isFunction(modelValue)) {
35044           modelValue = invokeModelGetter($scope);
35045         }
35046         return modelValue;
35047       };
35048       ngModelSet = function($scope, newValue) {
35049         if (isFunction(parsedNgModel($scope))) {
35050           invokeModelSetter($scope, {$$$p: ctrl.$modelValue});
35051         } else {
35052           parsedNgModelAssign($scope, ctrl.$modelValue);
35053         }
35054       };
35055     } else if (!parsedNgModel.assign) {
35056       throw ngModelMinErr('nonassign', "Expression '{0}' is non-assignable. Element: {1}",
35057           $attr.ngModel, startingTag($element));
35058     }
35059   };
35060
35061   /**
35062    * @ngdoc method
35063    * @name ngModel.NgModelController#$render
35064    *
35065    * @description
35066    * Called when the view needs to be updated. It is expected that the user of the ng-model
35067    * directive will implement this method.
35068    *
35069    * The `$render()` method is invoked in the following situations:
35070    *
35071    * * `$rollbackViewValue()` is called.  If we are rolling back the view value to the last
35072    *   committed value then `$render()` is called to update the input control.
35073    * * The value referenced by `ng-model` is changed programmatically and both the `$modelValue` and
35074    *   the `$viewValue` are different from last time.
35075    *
35076    * Since `ng-model` does not do a deep watch, `$render()` is only invoked if the values of
35077    * `$modelValue` and `$viewValue` are actually different from their previous value. If `$modelValue`
35078    * or `$viewValue` are objects (rather than a string or number) then `$render()` will not be
35079    * invoked if you only change a property on the objects.
35080    */
35081   this.$render = noop;
35082
35083   /**
35084    * @ngdoc method
35085    * @name ngModel.NgModelController#$isEmpty
35086    *
35087    * @description
35088    * This is called when we need to determine if the value of an input is empty.
35089    *
35090    * For instance, the required directive does this to work out if the input has data or not.
35091    *
35092    * The default `$isEmpty` function checks whether the value is `undefined`, `''`, `null` or `NaN`.
35093    *
35094    * You can override this for input directives whose concept of being empty is different from the
35095    * default. The `checkboxInputType` directive does this because in its case a value of `false`
35096    * implies empty.
35097    *
35098    * @param {*} value The value of the input to check for emptiness.
35099    * @returns {boolean} True if `value` is "empty".
35100    */
35101   this.$isEmpty = function(value) {
35102     return isUndefined(value) || value === '' || value === null || value !== value;
35103   };
35104
35105   this.$$updateEmptyClasses = function(value) {
35106     if (ctrl.$isEmpty(value)) {
35107       $animate.removeClass($element, NOT_EMPTY_CLASS);
35108       $animate.addClass($element, EMPTY_CLASS);
35109     } else {
35110       $animate.removeClass($element, EMPTY_CLASS);
35111       $animate.addClass($element, NOT_EMPTY_CLASS);
35112     }
35113   };
35114
35115
35116   var currentValidationRunId = 0;
35117
35118   /**
35119    * @ngdoc method
35120    * @name ngModel.NgModelController#$setValidity
35121    *
35122    * @description
35123    * Change the validity state, and notify the form.
35124    *
35125    * This method can be called within $parsers/$formatters or a custom validation implementation.
35126    * However, in most cases it should be sufficient to use the `ngModel.$validators` and
35127    * `ngModel.$asyncValidators` collections which will call `$setValidity` automatically.
35128    *
35129    * @param {string} validationErrorKey Name of the validator. The `validationErrorKey` will be assigned
35130    *        to either `$error[validationErrorKey]` or `$pending[validationErrorKey]`
35131    *        (for unfulfilled `$asyncValidators`), so that it is available for data-binding.
35132    *        The `validationErrorKey` should be in camelCase and will get converted into dash-case
35133    *        for class name. Example: `myError` will result in `ng-valid-my-error` and `ng-invalid-my-error`
35134    *        class and can be bound to as  `{{someForm.someControl.$error.myError}}` .
35135    * @param {boolean} isValid Whether the current state is valid (true), invalid (false), pending (undefined),
35136    *                          or skipped (null). Pending is used for unfulfilled `$asyncValidators`.
35137    *                          Skipped is used by Angular when validators do not run because of parse errors and
35138    *                          when `$asyncValidators` do not run because any of the `$validators` failed.
35139    */
35140   addSetValidityMethod({
35141     ctrl: this,
35142     $element: $element,
35143     set: function(object, property) {
35144       object[property] = true;
35145     },
35146     unset: function(object, property) {
35147       delete object[property];
35148     },
35149     $animate: $animate
35150   });
35151
35152   /**
35153    * @ngdoc method
35154    * @name ngModel.NgModelController#$setPristine
35155    *
35156    * @description
35157    * Sets the control to its pristine state.
35158    *
35159    * This method can be called to remove the `ng-dirty` class and set the control to its pristine
35160    * state (`ng-pristine` class). A model is considered to be pristine when the control
35161    * has not been changed from when first compiled.
35162    */
35163   this.$setPristine = function() {
35164     ctrl.$dirty = false;
35165     ctrl.$pristine = true;
35166     $animate.removeClass($element, DIRTY_CLASS);
35167     $animate.addClass($element, PRISTINE_CLASS);
35168   };
35169
35170   /**
35171    * @ngdoc method
35172    * @name ngModel.NgModelController#$setDirty
35173    *
35174    * @description
35175    * Sets the control to its dirty state.
35176    *
35177    * This method can be called to remove the `ng-pristine` class and set the control to its dirty
35178    * state (`ng-dirty` class). A model is considered to be dirty when the control has been changed
35179    * from when first compiled.
35180    */
35181   this.$setDirty = function() {
35182     ctrl.$dirty = true;
35183     ctrl.$pristine = false;
35184     $animate.removeClass($element, PRISTINE_CLASS);
35185     $animate.addClass($element, DIRTY_CLASS);
35186     ctrl.$$parentForm.$setDirty();
35187   };
35188
35189   /**
35190    * @ngdoc method
35191    * @name ngModel.NgModelController#$setUntouched
35192    *
35193    * @description
35194    * Sets the control to its untouched state.
35195    *
35196    * This method can be called to remove the `ng-touched` class and set the control to its
35197    * untouched state (`ng-untouched` class). Upon compilation, a model is set as untouched
35198    * by default, however this function can be used to restore that state if the model has
35199    * already been touched by the user.
35200    */
35201   this.$setUntouched = function() {
35202     ctrl.$touched = false;
35203     ctrl.$untouched = true;
35204     $animate.setClass($element, UNTOUCHED_CLASS, TOUCHED_CLASS);
35205   };
35206
35207   /**
35208    * @ngdoc method
35209    * @name ngModel.NgModelController#$setTouched
35210    *
35211    * @description
35212    * Sets the control to its touched state.
35213    *
35214    * This method can be called to remove the `ng-untouched` class and set the control to its
35215    * touched state (`ng-touched` class). A model is considered to be touched when the user has
35216    * first focused the control element and then shifted focus away from the control (blur event).
35217    */
35218   this.$setTouched = function() {
35219     ctrl.$touched = true;
35220     ctrl.$untouched = false;
35221     $animate.setClass($element, TOUCHED_CLASS, UNTOUCHED_CLASS);
35222   };
35223
35224   /**
35225    * @ngdoc method
35226    * @name ngModel.NgModelController#$rollbackViewValue
35227    *
35228    * @description
35229    * Cancel an update and reset the input element's value to prevent an update to the `$modelValue`,
35230    * which may be caused by a pending debounced event or because the input is waiting for a some
35231    * future event.
35232    *
35233    * If you have an input that uses `ng-model-options` to set up debounced updates or updates that
35234    * depend on special events such as blur, you can have a situation where there is a period when
35235    * the `$viewValue` is out of sync with the ngModel's `$modelValue`.
35236    *
35237    * In this case, you can use `$rollbackViewValue()` to manually cancel the debounced / future update
35238    * and reset the input to the last committed view value.
35239    *
35240    * It is also possible that you run into difficulties if you try to update the ngModel's `$modelValue`
35241    * programmatically before these debounced/future events have resolved/occurred, because Angular's
35242    * dirty checking mechanism is not able to tell whether the model has actually changed or not.
35243    *
35244    * The `$rollbackViewValue()` method should be called before programmatically changing the model of an
35245    * input which may have such events pending. This is important in order to make sure that the
35246    * input field will be updated with the new model value and any pending operations are cancelled.
35247    *
35248    * <example name="ng-model-cancel-update" module="cancel-update-example">
35249    *   <file name="app.js">
35250    *     angular.module('cancel-update-example', [])
35251    *
35252    *     .controller('CancelUpdateController', ['$scope', function($scope) {
35253    *       $scope.model = {};
35254    *
35255    *       $scope.setEmpty = function(e, value, rollback) {
35256    *         if (e.keyCode == 27) {
35257    *           e.preventDefault();
35258    *           if (rollback) {
35259    *             $scope.myForm[value].$rollbackViewValue();
35260    *           }
35261    *           $scope.model[value] = '';
35262    *         }
35263    *       };
35264    *     }]);
35265    *   </file>
35266    *   <file name="index.html">
35267    *     <div ng-controller="CancelUpdateController">
35268    *        <p>Both of these inputs are only updated if they are blurred. Hitting escape should
35269    *        empty them. Follow these steps and observe the difference:</p>
35270    *       <ol>
35271    *         <li>Type something in the input. You will see that the model is not yet updated</li>
35272    *         <li>Press the Escape key.
35273    *           <ol>
35274    *             <li> In the first example, nothing happens, because the model is already '', and no
35275    *             update is detected. If you blur the input, the model will be set to the current view.
35276    *             </li>
35277    *             <li> In the second example, the pending update is cancelled, and the input is set back
35278    *             to the last committed view value (''). Blurring the input does nothing.
35279    *             </li>
35280    *           </ol>
35281    *         </li>
35282    *       </ol>
35283    *
35284    *       <form name="myForm" ng-model-options="{ updateOn: 'blur' }">
35285    *         <div>
35286    *        <p id="inputDescription1">Without $rollbackViewValue():</p>
35287    *         <input name="value1" aria-describedby="inputDescription1" ng-model="model.value1"
35288    *                ng-keydown="setEmpty($event, 'value1')">
35289    *         value1: "{{ model.value1 }}"
35290    *         </div>
35291    *
35292    *         <div>
35293    *        <p id="inputDescription2">With $rollbackViewValue():</p>
35294    *         <input name="value2" aria-describedby="inputDescription2" ng-model="model.value2"
35295    *                ng-keydown="setEmpty($event, 'value2', true)">
35296    *         value2: "{{ model.value2 }}"
35297    *         </div>
35298    *       </form>
35299    *     </div>
35300    *   </file>
35301        <file name="style.css">
35302           div {
35303             display: table-cell;
35304           }
35305           div:nth-child(1) {
35306             padding-right: 30px;
35307           }
35308
35309         </file>
35310    * </example>
35311    */
35312   this.$rollbackViewValue = function() {
35313     $timeout.cancel(pendingDebounce);
35314     ctrl.$viewValue = ctrl.$$lastCommittedViewValue;
35315     ctrl.$render();
35316   };
35317
35318   /**
35319    * @ngdoc method
35320    * @name ngModel.NgModelController#$validate
35321    *
35322    * @description
35323    * Runs each of the registered validators (first synchronous validators and then
35324    * asynchronous validators).
35325    * If the validity changes to invalid, the model will be set to `undefined`,
35326    * unless {@link ngModelOptions `ngModelOptions.allowInvalid`} is `true`.
35327    * If the validity changes to valid, it will set the model to the last available valid
35328    * `$modelValue`, i.e. either the last parsed value or the last value set from the scope.
35329    */
35330   this.$validate = function() {
35331     // ignore $validate before model is initialized
35332     if (isNumber(ctrl.$modelValue) && isNaN(ctrl.$modelValue)) {
35333       return;
35334     }
35335
35336     var viewValue = ctrl.$$lastCommittedViewValue;
35337     // Note: we use the $$rawModelValue as $modelValue might have been
35338     // set to undefined during a view -> model update that found validation
35339     // errors. We can't parse the view here, since that could change
35340     // the model although neither viewValue nor the model on the scope changed
35341     var modelValue = ctrl.$$rawModelValue;
35342
35343     var prevValid = ctrl.$valid;
35344     var prevModelValue = ctrl.$modelValue;
35345
35346     var allowInvalid = ctrl.$options && ctrl.$options.allowInvalid;
35347
35348     ctrl.$$runValidators(modelValue, viewValue, function(allValid) {
35349       // If there was no change in validity, don't update the model
35350       // This prevents changing an invalid modelValue to undefined
35351       if (!allowInvalid && prevValid !== allValid) {
35352         // Note: Don't check ctrl.$valid here, as we could have
35353         // external validators (e.g. calculated on the server),
35354         // that just call $setValidity and need the model value
35355         // to calculate their validity.
35356         ctrl.$modelValue = allValid ? modelValue : undefined;
35357
35358         if (ctrl.$modelValue !== prevModelValue) {
35359           ctrl.$$writeModelToScope();
35360         }
35361       }
35362     });
35363
35364   };
35365
35366   this.$$runValidators = function(modelValue, viewValue, doneCallback) {
35367     currentValidationRunId++;
35368     var localValidationRunId = currentValidationRunId;
35369
35370     // check parser error
35371     if (!processParseErrors()) {
35372       validationDone(false);
35373       return;
35374     }
35375     if (!processSyncValidators()) {
35376       validationDone(false);
35377       return;
35378     }
35379     processAsyncValidators();
35380
35381     function processParseErrors() {
35382       var errorKey = ctrl.$$parserName || 'parse';
35383       if (isUndefined(parserValid)) {
35384         setValidity(errorKey, null);
35385       } else {
35386         if (!parserValid) {
35387           forEach(ctrl.$validators, function(v, name) {
35388             setValidity(name, null);
35389           });
35390           forEach(ctrl.$asyncValidators, function(v, name) {
35391             setValidity(name, null);
35392           });
35393         }
35394         // Set the parse error last, to prevent unsetting it, should a $validators key == parserName
35395         setValidity(errorKey, parserValid);
35396         return parserValid;
35397       }
35398       return true;
35399     }
35400
35401     function processSyncValidators() {
35402       var syncValidatorsValid = true;
35403       forEach(ctrl.$validators, function(validator, name) {
35404         var result = validator(modelValue, viewValue);
35405         syncValidatorsValid = syncValidatorsValid && result;
35406         setValidity(name, result);
35407       });
35408       if (!syncValidatorsValid) {
35409         forEach(ctrl.$asyncValidators, function(v, name) {
35410           setValidity(name, null);
35411         });
35412         return false;
35413       }
35414       return true;
35415     }
35416
35417     function processAsyncValidators() {
35418       var validatorPromises = [];
35419       var allValid = true;
35420       forEach(ctrl.$asyncValidators, function(validator, name) {
35421         var promise = validator(modelValue, viewValue);
35422         if (!isPromiseLike(promise)) {
35423           throw ngModelMinErr('nopromise',
35424             "Expected asynchronous validator to return a promise but got '{0}' instead.", promise);
35425         }
35426         setValidity(name, undefined);
35427         validatorPromises.push(promise.then(function() {
35428           setValidity(name, true);
35429         }, function(error) {
35430           allValid = false;
35431           setValidity(name, false);
35432         }));
35433       });
35434       if (!validatorPromises.length) {
35435         validationDone(true);
35436       } else {
35437         $q.all(validatorPromises).then(function() {
35438           validationDone(allValid);
35439         }, noop);
35440       }
35441     }
35442
35443     function setValidity(name, isValid) {
35444       if (localValidationRunId === currentValidationRunId) {
35445         ctrl.$setValidity(name, isValid);
35446       }
35447     }
35448
35449     function validationDone(allValid) {
35450       if (localValidationRunId === currentValidationRunId) {
35451
35452         doneCallback(allValid);
35453       }
35454     }
35455   };
35456
35457   /**
35458    * @ngdoc method
35459    * @name ngModel.NgModelController#$commitViewValue
35460    *
35461    * @description
35462    * Commit a pending update to the `$modelValue`.
35463    *
35464    * Updates may be pending by a debounced event or because the input is waiting for a some future
35465    * event defined in `ng-model-options`. this method is rarely needed as `NgModelController`
35466    * usually handles calling this in response to input events.
35467    */
35468   this.$commitViewValue = function() {
35469     var viewValue = ctrl.$viewValue;
35470
35471     $timeout.cancel(pendingDebounce);
35472
35473     // If the view value has not changed then we should just exit, except in the case where there is
35474     // a native validator on the element. In this case the validation state may have changed even though
35475     // the viewValue has stayed empty.
35476     if (ctrl.$$lastCommittedViewValue === viewValue && (viewValue !== '' || !ctrl.$$hasNativeValidators)) {
35477       return;
35478     }
35479     ctrl.$$updateEmptyClasses(viewValue);
35480     ctrl.$$lastCommittedViewValue = viewValue;
35481
35482     // change to dirty
35483     if (ctrl.$pristine) {
35484       this.$setDirty();
35485     }
35486     this.$$parseAndValidate();
35487   };
35488
35489   this.$$parseAndValidate = function() {
35490     var viewValue = ctrl.$$lastCommittedViewValue;
35491     var modelValue = viewValue;
35492     parserValid = isUndefined(modelValue) ? undefined : true;
35493
35494     if (parserValid) {
35495       for (var i = 0; i < ctrl.$parsers.length; i++) {
35496         modelValue = ctrl.$parsers[i](modelValue);
35497         if (isUndefined(modelValue)) {
35498           parserValid = false;
35499           break;
35500         }
35501       }
35502     }
35503     if (isNumber(ctrl.$modelValue) && isNaN(ctrl.$modelValue)) {
35504       // ctrl.$modelValue has not been touched yet...
35505       ctrl.$modelValue = ngModelGet($scope);
35506     }
35507     var prevModelValue = ctrl.$modelValue;
35508     var allowInvalid = ctrl.$options && ctrl.$options.allowInvalid;
35509     ctrl.$$rawModelValue = modelValue;
35510
35511     if (allowInvalid) {
35512       ctrl.$modelValue = modelValue;
35513       writeToModelIfNeeded();
35514     }
35515
35516     // Pass the $$lastCommittedViewValue here, because the cached viewValue might be out of date.
35517     // This can happen if e.g. $setViewValue is called from inside a parser
35518     ctrl.$$runValidators(modelValue, ctrl.$$lastCommittedViewValue, function(allValid) {
35519       if (!allowInvalid) {
35520         // Note: Don't check ctrl.$valid here, as we could have
35521         // external validators (e.g. calculated on the server),
35522         // that just call $setValidity and need the model value
35523         // to calculate their validity.
35524         ctrl.$modelValue = allValid ? modelValue : undefined;
35525         writeToModelIfNeeded();
35526       }
35527     });
35528
35529     function writeToModelIfNeeded() {
35530       if (ctrl.$modelValue !== prevModelValue) {
35531         ctrl.$$writeModelToScope();
35532       }
35533     }
35534   };
35535
35536   this.$$writeModelToScope = function() {
35537     ngModelSet($scope, ctrl.$modelValue);
35538     forEach(ctrl.$viewChangeListeners, function(listener) {
35539       try {
35540         listener();
35541       } catch (e) {
35542         $exceptionHandler(e);
35543       }
35544     });
35545   };
35546
35547   /**
35548    * @ngdoc method
35549    * @name ngModel.NgModelController#$setViewValue
35550    *
35551    * @description
35552    * Update the view value.
35553    *
35554    * This method should be called when a control wants to change the view value; typically,
35555    * this is done from within a DOM event handler. For example, the {@link ng.directive:input input}
35556    * directive calls it when the value of the input changes and {@link ng.directive:select select}
35557    * calls it when an option is selected.
35558    *
35559    * When `$setViewValue` is called, the new `value` will be staged for committing through the `$parsers`
35560    * and `$validators` pipelines. If there are no special {@link ngModelOptions} specified then the staged
35561    * value sent directly for processing, finally to be applied to `$modelValue` and then the
35562    * **expression** specified in the `ng-model` attribute. Lastly, all the registered change listeners,
35563    * in the `$viewChangeListeners` list, are called.
35564    *
35565    * In case the {@link ng.directive:ngModelOptions ngModelOptions} directive is used with `updateOn`
35566    * and the `default` trigger is not listed, all those actions will remain pending until one of the
35567    * `updateOn` events is triggered on the DOM element.
35568    * All these actions will be debounced if the {@link ng.directive:ngModelOptions ngModelOptions}
35569    * directive is used with a custom debounce for this particular event.
35570    * Note that a `$digest` is only triggered once the `updateOn` events are fired, or if `debounce`
35571    * is specified, once the timer runs out.
35572    *
35573    * When used with standard inputs, the view value will always be a string (which is in some cases
35574    * parsed into another type, such as a `Date` object for `input[date]`.)
35575    * However, custom controls might also pass objects to this method. In this case, we should make
35576    * a copy of the object before passing it to `$setViewValue`. This is because `ngModel` does not
35577    * perform a deep watch of objects, it only looks for a change of identity. If you only change
35578    * the property of the object then ngModel will not realize that the object has changed and
35579    * will not invoke the `$parsers` and `$validators` pipelines. For this reason, you should
35580    * not change properties of the copy once it has been passed to `$setViewValue`.
35581    * Otherwise you may cause the model value on the scope to change incorrectly.
35582    *
35583    * <div class="alert alert-info">
35584    * In any case, the value passed to the method should always reflect the current value
35585    * of the control. For example, if you are calling `$setViewValue` for an input element,
35586    * you should pass the input DOM value. Otherwise, the control and the scope model become
35587    * out of sync. It's also important to note that `$setViewValue` does not call `$render` or change
35588    * the control's DOM value in any way. If we want to change the control's DOM value
35589    * programmatically, we should update the `ngModel` scope expression. Its new value will be
35590    * picked up by the model controller, which will run it through the `$formatters`, `$render` it
35591    * to update the DOM, and finally call `$validate` on it.
35592    * </div>
35593    *
35594    * @param {*} value value from the view.
35595    * @param {string} trigger Event that triggered the update.
35596    */
35597   this.$setViewValue = function(value, trigger) {
35598     ctrl.$viewValue = value;
35599     if (!ctrl.$options || ctrl.$options.updateOnDefault) {
35600       ctrl.$$debounceViewValueCommit(trigger);
35601     }
35602   };
35603
35604   this.$$debounceViewValueCommit = function(trigger) {
35605     var debounceDelay = 0,
35606         options = ctrl.$options,
35607         debounce;
35608
35609     if (options && isDefined(options.debounce)) {
35610       debounce = options.debounce;
35611       if (isNumber(debounce)) {
35612         debounceDelay = debounce;
35613       } else if (isNumber(debounce[trigger])) {
35614         debounceDelay = debounce[trigger];
35615       } else if (isNumber(debounce['default'])) {
35616         debounceDelay = debounce['default'];
35617       }
35618     }
35619
35620     $timeout.cancel(pendingDebounce);
35621     if (debounceDelay) {
35622       pendingDebounce = $timeout(function() {
35623         ctrl.$commitViewValue();
35624       }, debounceDelay);
35625     } else if ($rootScope.$$phase) {
35626       ctrl.$commitViewValue();
35627     } else {
35628       $scope.$apply(function() {
35629         ctrl.$commitViewValue();
35630       });
35631     }
35632   };
35633
35634   // model -> value
35635   // Note: we cannot use a normal scope.$watch as we want to detect the following:
35636   // 1. scope value is 'a'
35637   // 2. user enters 'b'
35638   // 3. ng-change kicks in and reverts scope value to 'a'
35639   //    -> scope value did not change since the last digest as
35640   //       ng-change executes in apply phase
35641   // 4. view should be changed back to 'a'
35642   $scope.$watch(function ngModelWatch() {
35643     var modelValue = ngModelGet($scope);
35644
35645     // if scope model value and ngModel value are out of sync
35646     // TODO(perf): why not move this to the action fn?
35647     if (modelValue !== ctrl.$modelValue &&
35648        // checks for NaN is needed to allow setting the model to NaN when there's an asyncValidator
35649        (ctrl.$modelValue === ctrl.$modelValue || modelValue === modelValue)
35650     ) {
35651       ctrl.$modelValue = ctrl.$$rawModelValue = modelValue;
35652       parserValid = undefined;
35653
35654       var formatters = ctrl.$formatters,
35655           idx = formatters.length;
35656
35657       var viewValue = modelValue;
35658       while (idx--) {
35659         viewValue = formatters[idx](viewValue);
35660       }
35661       if (ctrl.$viewValue !== viewValue) {
35662         ctrl.$$updateEmptyClasses(viewValue);
35663         ctrl.$viewValue = ctrl.$$lastCommittedViewValue = viewValue;
35664         ctrl.$render();
35665
35666         ctrl.$$runValidators(modelValue, viewValue, noop);
35667       }
35668     }
35669
35670     return modelValue;
35671   });
35672 }];
35673
35674
35675 /**
35676  * @ngdoc directive
35677  * @name ngModel
35678  *
35679  * @element input
35680  * @priority 1
35681  *
35682  * @description
35683  * The `ngModel` directive binds an `input`,`select`, `textarea` (or custom form control) to a
35684  * property on the scope using {@link ngModel.NgModelController NgModelController},
35685  * which is created and exposed by this directive.
35686  *
35687  * `ngModel` is responsible for:
35688  *
35689  * - Binding the view into the model, which other directives such as `input`, `textarea` or `select`
35690  *   require.
35691  * - Providing validation behavior (i.e. required, number, email, url).
35692  * - Keeping the state of the control (valid/invalid, dirty/pristine, touched/untouched, validation errors).
35693  * - Setting related css classes on the element (`ng-valid`, `ng-invalid`, `ng-dirty`, `ng-pristine`, `ng-touched`,
35694  *   `ng-untouched`, `ng-empty`, `ng-not-empty`) including animations.
35695  * - Registering the control with its parent {@link ng.directive:form form}.
35696  *
35697  * Note: `ngModel` will try to bind to the property given by evaluating the expression on the
35698  * current scope. If the property doesn't already exist on this scope, it will be created
35699  * implicitly and added to the scope.
35700  *
35701  * For best practices on using `ngModel`, see:
35702  *
35703  *  - [Understanding Scopes](https://github.com/angular/angular.js/wiki/Understanding-Scopes)
35704  *
35705  * For basic examples, how to use `ngModel`, see:
35706  *
35707  *  - {@link ng.directive:input input}
35708  *    - {@link input[text] text}
35709  *    - {@link input[checkbox] checkbox}
35710  *    - {@link input[radio] radio}
35711  *    - {@link input[number] number}
35712  *    - {@link input[email] email}
35713  *    - {@link input[url] url}
35714  *    - {@link input[date] date}
35715  *    - {@link input[datetime-local] datetime-local}
35716  *    - {@link input[time] time}
35717  *    - {@link input[month] month}
35718  *    - {@link input[week] week}
35719  *  - {@link ng.directive:select select}
35720  *  - {@link ng.directive:textarea textarea}
35721  *
35722  * # Complex Models (objects or collections)
35723  *
35724  * By default, `ngModel` watches the model by reference, not value. This is important to know when
35725  * binding inputs to models that are objects (e.g. `Date`) or collections (e.g. arrays). If only properties of the
35726  * object or collection change, `ngModel` will not be notified and so the input will not be  re-rendered.
35727  *
35728  * The model must be assigned an entirely new object or collection before a re-rendering will occur.
35729  *
35730  * Some directives have options that will cause them to use a custom `$watchCollection` on the model expression
35731  * - for example, `ngOptions` will do so when a `track by` clause is included in the comprehension expression or
35732  * if the select is given the `multiple` attribute.
35733  *
35734  * The `$watchCollection()` method only does a shallow comparison, meaning that changing properties deeper than the
35735  * first level of the object (or only changing the properties of an item in the collection if it's an array) will still
35736  * not trigger a re-rendering of the model.
35737  *
35738  * # CSS classes
35739  * The following CSS classes are added and removed on the associated input/select/textarea element
35740  * depending on the validity of the model.
35741  *
35742  *  - `ng-valid`: the model is valid
35743  *  - `ng-invalid`: the model is invalid
35744  *  - `ng-valid-[key]`: for each valid key added by `$setValidity`
35745  *  - `ng-invalid-[key]`: for each invalid key added by `$setValidity`
35746  *  - `ng-pristine`: the control hasn't been interacted with yet
35747  *  - `ng-dirty`: the control has been interacted with
35748  *  - `ng-touched`: the control has been blurred
35749  *  - `ng-untouched`: the control hasn't been blurred
35750  *  - `ng-pending`: any `$asyncValidators` are unfulfilled
35751  *  - `ng-empty`: the view does not contain a value or the value is deemed "empty", as defined
35752  *     by the {@link ngModel.NgModelController#$isEmpty} method
35753  *  - `ng-not-empty`: the view contains a non-empty value
35754  *
35755  * Keep in mind that ngAnimate can detect each of these classes when added and removed.
35756  *
35757  * ## Animation Hooks
35758  *
35759  * Animations within models are triggered when any of the associated CSS classes are added and removed
35760  * on the input element which is attached to the model. These classes include: `.ng-pristine`, `.ng-dirty`,
35761  * `.ng-invalid` and `.ng-valid` as well as any other validations that are performed on the model itself.
35762  * The animations that are triggered within ngModel are similar to how they work in ngClass and
35763  * animations can be hooked into using CSS transitions, keyframes as well as JS animations.
35764  *
35765  * The following example shows a simple way to utilize CSS transitions to style an input element
35766  * that has been rendered as invalid after it has been validated:
35767  *
35768  * <pre>
35769  * //be sure to include ngAnimate as a module to hook into more
35770  * //advanced animations
35771  * .my-input {
35772  *   transition:0.5s linear all;
35773  *   background: white;
35774  * }
35775  * .my-input.ng-invalid {
35776  *   background: red;
35777  *   color:white;
35778  * }
35779  * </pre>
35780  *
35781  * @example
35782  * <example deps="angular-animate.js" animations="true" fixBase="true" module="inputExample">
35783      <file name="index.html">
35784        <script>
35785         angular.module('inputExample', [])
35786           .controller('ExampleController', ['$scope', function($scope) {
35787             $scope.val = '1';
35788           }]);
35789        </script>
35790        <style>
35791          .my-input {
35792            transition:all linear 0.5s;
35793            background: transparent;
35794          }
35795          .my-input.ng-invalid {
35796            color:white;
35797            background: red;
35798          }
35799        </style>
35800        <p id="inputDescription">
35801         Update input to see transitions when valid/invalid.
35802         Integer is a valid value.
35803        </p>
35804        <form name="testForm" ng-controller="ExampleController">
35805          <input ng-model="val" ng-pattern="/^\d+$/" name="anim" class="my-input"
35806                 aria-describedby="inputDescription" />
35807        </form>
35808      </file>
35809  * </example>
35810  *
35811  * ## Binding to a getter/setter
35812  *
35813  * Sometimes it's helpful to bind `ngModel` to a getter/setter function.  A getter/setter is a
35814  * function that returns a representation of the model when called with zero arguments, and sets
35815  * the internal state of a model when called with an argument. It's sometimes useful to use this
35816  * for models that have an internal representation that's different from what the model exposes
35817  * to the view.
35818  *
35819  * <div class="alert alert-success">
35820  * **Best Practice:** It's best to keep getters fast because Angular is likely to call them more
35821  * frequently than other parts of your code.
35822  * </div>
35823  *
35824  * You use this behavior by adding `ng-model-options="{ getterSetter: true }"` to an element that
35825  * has `ng-model` attached to it. You can also add `ng-model-options="{ getterSetter: true }"` to
35826  * a `<form>`, which will enable this behavior for all `<input>`s within it. See
35827  * {@link ng.directive:ngModelOptions `ngModelOptions`} for more.
35828  *
35829  * The following example shows how to use `ngModel` with a getter/setter:
35830  *
35831  * @example
35832  * <example name="ngModel-getter-setter" module="getterSetterExample">
35833      <file name="index.html">
35834        <div ng-controller="ExampleController">
35835          <form name="userForm">
35836            <label>Name:
35837              <input type="text" name="userName"
35838                     ng-model="user.name"
35839                     ng-model-options="{ getterSetter: true }" />
35840            </label>
35841          </form>
35842          <pre>user.name = <span ng-bind="user.name()"></span></pre>
35843        </div>
35844      </file>
35845      <file name="app.js">
35846        angular.module('getterSetterExample', [])
35847          .controller('ExampleController', ['$scope', function($scope) {
35848            var _name = 'Brian';
35849            $scope.user = {
35850              name: function(newName) {
35851               // Note that newName can be undefined for two reasons:
35852               // 1. Because it is called as a getter and thus called with no arguments
35853               // 2. Because the property should actually be set to undefined. This happens e.g. if the
35854               //    input is invalid
35855               return arguments.length ? (_name = newName) : _name;
35856              }
35857            };
35858          }]);
35859      </file>
35860  * </example>
35861  */
35862 var ngModelDirective = ['$rootScope', function($rootScope) {
35863   return {
35864     restrict: 'A',
35865     require: ['ngModel', '^?form', '^?ngModelOptions'],
35866     controller: NgModelController,
35867     // Prelink needs to run before any input directive
35868     // so that we can set the NgModelOptions in NgModelController
35869     // before anyone else uses it.
35870     priority: 1,
35871     compile: function ngModelCompile(element) {
35872       // Setup initial state of the control
35873       element.addClass(PRISTINE_CLASS).addClass(UNTOUCHED_CLASS).addClass(VALID_CLASS);
35874
35875       return {
35876         pre: function ngModelPreLink(scope, element, attr, ctrls) {
35877           var modelCtrl = ctrls[0],
35878               formCtrl = ctrls[1] || modelCtrl.$$parentForm;
35879
35880           modelCtrl.$$setOptions(ctrls[2] && ctrls[2].$options);
35881
35882           // notify others, especially parent forms
35883           formCtrl.$addControl(modelCtrl);
35884
35885           attr.$observe('name', function(newValue) {
35886             if (modelCtrl.$name !== newValue) {
35887               modelCtrl.$$parentForm.$$renameControl(modelCtrl, newValue);
35888             }
35889           });
35890
35891           scope.$on('$destroy', function() {
35892             modelCtrl.$$parentForm.$removeControl(modelCtrl);
35893           });
35894         },
35895         post: function ngModelPostLink(scope, element, attr, ctrls) {
35896           var modelCtrl = ctrls[0];
35897           if (modelCtrl.$options && modelCtrl.$options.updateOn) {
35898             element.on(modelCtrl.$options.updateOn, function(ev) {
35899               modelCtrl.$$debounceViewValueCommit(ev && ev.type);
35900             });
35901           }
35902
35903           element.on('blur', function(ev) {
35904             if (modelCtrl.$touched) return;
35905
35906             if ($rootScope.$$phase) {
35907               scope.$evalAsync(modelCtrl.$setTouched);
35908             } else {
35909               scope.$apply(modelCtrl.$setTouched);
35910             }
35911           });
35912         }
35913       };
35914     }
35915   };
35916 }];
35917
35918 var DEFAULT_REGEXP = /(\s+|^)default(\s+|$)/;
35919
35920 /**
35921  * @ngdoc directive
35922  * @name ngModelOptions
35923  *
35924  * @description
35925  * Allows tuning how model updates are done. Using `ngModelOptions` you can specify a custom list of
35926  * events that will trigger a model update and/or a debouncing delay so that the actual update only
35927  * takes place when a timer expires; this timer will be reset after another change takes place.
35928  *
35929  * Given the nature of `ngModelOptions`, the value displayed inside input fields in the view might
35930  * be different from the value in the actual model. This means that if you update the model you
35931  * should also invoke {@link ngModel.NgModelController `$rollbackViewValue`} on the relevant input field in
35932  * order to make sure it is synchronized with the model and that any debounced action is canceled.
35933  *
35934  * The easiest way to reference the control's {@link ngModel.NgModelController `$rollbackViewValue`}
35935  * method is by making sure the input is placed inside a form that has a `name` attribute. This is
35936  * important because `form` controllers are published to the related scope under the name in their
35937  * `name` attribute.
35938  *
35939  * Any pending changes will take place immediately when an enclosing form is submitted via the
35940  * `submit` event. Note that `ngClick` events will occur before the model is updated. Use `ngSubmit`
35941  * to have access to the updated model.
35942  *
35943  * `ngModelOptions` has an effect on the element it's declared on and its descendants.
35944  *
35945  * @param {Object} ngModelOptions options to apply to the current model. Valid keys are:
35946  *   - `updateOn`: string specifying which event should the input be bound to. You can set several
35947  *     events using an space delimited list. There is a special event called `default` that
35948  *     matches the default events belonging of the control.
35949  *   - `debounce`: integer value which contains the debounce model update value in milliseconds. A
35950  *     value of 0 triggers an immediate update. If an object is supplied instead, you can specify a
35951  *     custom value for each event. For example:
35952  *     `ng-model-options="{ updateOn: 'default blur', debounce: { 'default': 500, 'blur': 0 } }"`
35953  *   - `allowInvalid`: boolean value which indicates that the model can be set with values that did
35954  *     not validate correctly instead of the default behavior of setting the model to undefined.
35955  *   - `getterSetter`: boolean value which determines whether or not to treat functions bound to
35956        `ngModel` as getters/setters.
35957  *   - `timezone`: Defines the timezone to be used to read/write the `Date` instance in the model for
35958  *     `<input type="date">`, `<input type="time">`, ... . It understands UTC/GMT and the
35959  *     continental US time zone abbreviations, but for general use, use a time zone offset, for
35960  *     example, `'+0430'` (4 hours, 30 minutes east of the Greenwich meridian)
35961  *     If not specified, the timezone of the browser will be used.
35962  *
35963  * @example
35964
35965   The following example shows how to override immediate updates. Changes on the inputs within the
35966   form will update the model only when the control loses focus (blur event). If `escape` key is
35967   pressed while the input field is focused, the value is reset to the value in the current model.
35968
35969   <example name="ngModelOptions-directive-blur" module="optionsExample">
35970     <file name="index.html">
35971       <div ng-controller="ExampleController">
35972         <form name="userForm">
35973           <label>Name:
35974             <input type="text" name="userName"
35975                    ng-model="user.name"
35976                    ng-model-options="{ updateOn: 'blur' }"
35977                    ng-keyup="cancel($event)" />
35978           </label><br />
35979           <label>Other data:
35980             <input type="text" ng-model="user.data" />
35981           </label><br />
35982         </form>
35983         <pre>user.name = <span ng-bind="user.name"></span></pre>
35984         <pre>user.data = <span ng-bind="user.data"></span></pre>
35985       </div>
35986     </file>
35987     <file name="app.js">
35988       angular.module('optionsExample', [])
35989         .controller('ExampleController', ['$scope', function($scope) {
35990           $scope.user = { name: 'John', data: '' };
35991
35992           $scope.cancel = function(e) {
35993             if (e.keyCode == 27) {
35994               $scope.userForm.userName.$rollbackViewValue();
35995             }
35996           };
35997         }]);
35998     </file>
35999     <file name="protractor.js" type="protractor">
36000       var model = element(by.binding('user.name'));
36001       var input = element(by.model('user.name'));
36002       var other = element(by.model('user.data'));
36003
36004       it('should allow custom events', function() {
36005         input.sendKeys(' Doe');
36006         input.click();
36007         expect(model.getText()).toEqual('John');
36008         other.click();
36009         expect(model.getText()).toEqual('John Doe');
36010       });
36011
36012       it('should $rollbackViewValue when model changes', function() {
36013         input.sendKeys(' Doe');
36014         expect(input.getAttribute('value')).toEqual('John Doe');
36015         input.sendKeys(protractor.Key.ESCAPE);
36016         expect(input.getAttribute('value')).toEqual('John');
36017         other.click();
36018         expect(model.getText()).toEqual('John');
36019       });
36020     </file>
36021   </example>
36022
36023   This one shows how to debounce model changes. Model will be updated only 1 sec after last change.
36024   If the `Clear` button is pressed, any debounced action is canceled and the value becomes empty.
36025
36026   <example name="ngModelOptions-directive-debounce" module="optionsExample">
36027     <file name="index.html">
36028       <div ng-controller="ExampleController">
36029         <form name="userForm">
36030           <label>Name:
36031             <input type="text" name="userName"
36032                    ng-model="user.name"
36033                    ng-model-options="{ debounce: 1000 }" />
36034           </label>
36035           <button ng-click="userForm.userName.$rollbackViewValue(); user.name=''">Clear</button>
36036           <br />
36037         </form>
36038         <pre>user.name = <span ng-bind="user.name"></span></pre>
36039       </div>
36040     </file>
36041     <file name="app.js">
36042       angular.module('optionsExample', [])
36043         .controller('ExampleController', ['$scope', function($scope) {
36044           $scope.user = { name: 'Igor' };
36045         }]);
36046     </file>
36047   </example>
36048
36049   This one shows how to bind to getter/setters:
36050
36051   <example name="ngModelOptions-directive-getter-setter" module="getterSetterExample">
36052     <file name="index.html">
36053       <div ng-controller="ExampleController">
36054         <form name="userForm">
36055           <label>Name:
36056             <input type="text" name="userName"
36057                    ng-model="user.name"
36058                    ng-model-options="{ getterSetter: true }" />
36059           </label>
36060         </form>
36061         <pre>user.name = <span ng-bind="user.name()"></span></pre>
36062       </div>
36063     </file>
36064     <file name="app.js">
36065       angular.module('getterSetterExample', [])
36066         .controller('ExampleController', ['$scope', function($scope) {
36067           var _name = 'Brian';
36068           $scope.user = {
36069             name: function(newName) {
36070               // Note that newName can be undefined for two reasons:
36071               // 1. Because it is called as a getter and thus called with no arguments
36072               // 2. Because the property should actually be set to undefined. This happens e.g. if the
36073               //    input is invalid
36074               return arguments.length ? (_name = newName) : _name;
36075             }
36076           };
36077         }]);
36078     </file>
36079   </example>
36080  */
36081 var ngModelOptionsDirective = function() {
36082   return {
36083     restrict: 'A',
36084     controller: ['$scope', '$attrs', function($scope, $attrs) {
36085       var that = this;
36086       this.$options = copy($scope.$eval($attrs.ngModelOptions));
36087       // Allow adding/overriding bound events
36088       if (isDefined(this.$options.updateOn)) {
36089         this.$options.updateOnDefault = false;
36090         // extract "default" pseudo-event from list of events that can trigger a model update
36091         this.$options.updateOn = trim(this.$options.updateOn.replace(DEFAULT_REGEXP, function() {
36092           that.$options.updateOnDefault = true;
36093           return ' ';
36094         }));
36095       } else {
36096         this.$options.updateOnDefault = true;
36097       }
36098     }]
36099   };
36100 };
36101
36102
36103
36104 // helper methods
36105 function addSetValidityMethod(context) {
36106   var ctrl = context.ctrl,
36107       $element = context.$element,
36108       classCache = {},
36109       set = context.set,
36110       unset = context.unset,
36111       $animate = context.$animate;
36112
36113   classCache[INVALID_CLASS] = !(classCache[VALID_CLASS] = $element.hasClass(VALID_CLASS));
36114
36115   ctrl.$setValidity = setValidity;
36116
36117   function setValidity(validationErrorKey, state, controller) {
36118     if (isUndefined(state)) {
36119       createAndSet('$pending', validationErrorKey, controller);
36120     } else {
36121       unsetAndCleanup('$pending', validationErrorKey, controller);
36122     }
36123     if (!isBoolean(state)) {
36124       unset(ctrl.$error, validationErrorKey, controller);
36125       unset(ctrl.$$success, validationErrorKey, controller);
36126     } else {
36127       if (state) {
36128         unset(ctrl.$error, validationErrorKey, controller);
36129         set(ctrl.$$success, validationErrorKey, controller);
36130       } else {
36131         set(ctrl.$error, validationErrorKey, controller);
36132         unset(ctrl.$$success, validationErrorKey, controller);
36133       }
36134     }
36135     if (ctrl.$pending) {
36136       cachedToggleClass(PENDING_CLASS, true);
36137       ctrl.$valid = ctrl.$invalid = undefined;
36138       toggleValidationCss('', null);
36139     } else {
36140       cachedToggleClass(PENDING_CLASS, false);
36141       ctrl.$valid = isObjectEmpty(ctrl.$error);
36142       ctrl.$invalid = !ctrl.$valid;
36143       toggleValidationCss('', ctrl.$valid);
36144     }
36145
36146     // re-read the state as the set/unset methods could have
36147     // combined state in ctrl.$error[validationError] (used for forms),
36148     // where setting/unsetting only increments/decrements the value,
36149     // and does not replace it.
36150     var combinedState;
36151     if (ctrl.$pending && ctrl.$pending[validationErrorKey]) {
36152       combinedState = undefined;
36153     } else if (ctrl.$error[validationErrorKey]) {
36154       combinedState = false;
36155     } else if (ctrl.$$success[validationErrorKey]) {
36156       combinedState = true;
36157     } else {
36158       combinedState = null;
36159     }
36160
36161     toggleValidationCss(validationErrorKey, combinedState);
36162     ctrl.$$parentForm.$setValidity(validationErrorKey, combinedState, ctrl);
36163   }
36164
36165   function createAndSet(name, value, controller) {
36166     if (!ctrl[name]) {
36167       ctrl[name] = {};
36168     }
36169     set(ctrl[name], value, controller);
36170   }
36171
36172   function unsetAndCleanup(name, value, controller) {
36173     if (ctrl[name]) {
36174       unset(ctrl[name], value, controller);
36175     }
36176     if (isObjectEmpty(ctrl[name])) {
36177       ctrl[name] = undefined;
36178     }
36179   }
36180
36181   function cachedToggleClass(className, switchValue) {
36182     if (switchValue && !classCache[className]) {
36183       $animate.addClass($element, className);
36184       classCache[className] = true;
36185     } else if (!switchValue && classCache[className]) {
36186       $animate.removeClass($element, className);
36187       classCache[className] = false;
36188     }
36189   }
36190
36191   function toggleValidationCss(validationErrorKey, isValid) {
36192     validationErrorKey = validationErrorKey ? '-' + snake_case(validationErrorKey, '-') : '';
36193
36194     cachedToggleClass(VALID_CLASS + validationErrorKey, isValid === true);
36195     cachedToggleClass(INVALID_CLASS + validationErrorKey, isValid === false);
36196   }
36197 }
36198
36199 function isObjectEmpty(obj) {
36200   if (obj) {
36201     for (var prop in obj) {
36202       if (obj.hasOwnProperty(prop)) {
36203         return false;
36204       }
36205     }
36206   }
36207   return true;
36208 }
36209
36210 /**
36211  * @ngdoc directive
36212  * @name ngNonBindable
36213  * @restrict AC
36214  * @priority 1000
36215  *
36216  * @description
36217  * The `ngNonBindable` directive tells Angular not to compile or bind the contents of the current
36218  * DOM element. This is useful if the element contains what appears to be Angular directives and
36219  * bindings but which should be ignored by Angular. This could be the case if you have a site that
36220  * displays snippets of code, for instance.
36221  *
36222  * @element ANY
36223  *
36224  * @example
36225  * In this example there are two locations where a simple interpolation binding (`{{}}`) is present,
36226  * but the one wrapped in `ngNonBindable` is left alone.
36227  *
36228  * @example
36229     <example>
36230       <file name="index.html">
36231         <div>Normal: {{1 + 2}}</div>
36232         <div ng-non-bindable>Ignored: {{1 + 2}}</div>
36233       </file>
36234       <file name="protractor.js" type="protractor">
36235        it('should check ng-non-bindable', function() {
36236          expect(element(by.binding('1 + 2')).getText()).toContain('3');
36237          expect(element.all(by.css('div')).last().getText()).toMatch(/1 \+ 2/);
36238        });
36239       </file>
36240     </example>
36241  */
36242 var ngNonBindableDirective = ngDirective({ terminal: true, priority: 1000 });
36243
36244 /* global jqLiteRemove */
36245
36246 var ngOptionsMinErr = minErr('ngOptions');
36247
36248 /**
36249  * @ngdoc directive
36250  * @name ngOptions
36251  * @restrict A
36252  *
36253  * @description
36254  *
36255  * The `ngOptions` attribute can be used to dynamically generate a list of `<option>`
36256  * elements for the `<select>` element using the array or object obtained by evaluating the
36257  * `ngOptions` comprehension expression.
36258  *
36259  * In many cases, `ngRepeat` can be used on `<option>` elements instead of `ngOptions` to achieve a
36260  * similar result. However, `ngOptions` provides some benefits such as reducing memory and
36261  * increasing speed by not creating a new scope for each repeated instance, as well as providing
36262  * more flexibility in how the `<select>`'s model is assigned via the `select` **`as`** part of the
36263  * comprehension expression. `ngOptions` should be used when the `<select>` model needs to be bound
36264  *  to a non-string value. This is because an option element can only be bound to string values at
36265  * present.
36266  *
36267  * When an item in the `<select>` menu is selected, the array element or object property
36268  * represented by the selected option will be bound to the model identified by the `ngModel`
36269  * directive.
36270  *
36271  * Optionally, a single hard-coded `<option>` element, with the value set to an empty string, can
36272  * be nested into the `<select>` element. This element will then represent the `null` or "not selected"
36273  * option. See example below for demonstration.
36274  *
36275  * ## Complex Models (objects or collections)
36276  *
36277  * By default, `ngModel` watches the model by reference, not value. This is important to know when
36278  * binding the select to a model that is an object or a collection.
36279  *
36280  * One issue occurs if you want to preselect an option. For example, if you set
36281  * the model to an object that is equal to an object in your collection, `ngOptions` won't be able to set the selection,
36282  * because the objects are not identical. So by default, you should always reference the item in your collection
36283  * for preselections, e.g.: `$scope.selected = $scope.collection[3]`.
36284  *
36285  * Another solution is to use a `track by` clause, because then `ngOptions` will track the identity
36286  * of the item not by reference, but by the result of the `track by` expression. For example, if your
36287  * collection items have an id property, you would `track by item.id`.
36288  *
36289  * A different issue with objects or collections is that ngModel won't detect if an object property or
36290  * a collection item changes. For that reason, `ngOptions` additionally watches the model using
36291  * `$watchCollection`, when the expression contains a `track by` clause or the the select has the `multiple` attribute.
36292  * This allows ngOptions to trigger a re-rendering of the options even if the actual object/collection
36293  * has not changed identity, but only a property on the object or an item in the collection changes.
36294  *
36295  * Note that `$watchCollection` does a shallow comparison of the properties of the object (or the items in the collection
36296  * if the model is an array). This means that changing a property deeper than the first level inside the
36297  * object/collection will not trigger a re-rendering.
36298  *
36299  * ## `select` **`as`**
36300  *
36301  * Using `select` **`as`** will bind the result of the `select` expression to the model, but
36302  * the value of the `<select>` and `<option>` html elements will be either the index (for array data sources)
36303  * or property name (for object data sources) of the value within the collection. If a **`track by`** expression
36304  * is used, the result of that expression will be set as the value of the `option` and `select` elements.
36305  *
36306  *
36307  * ### `select` **`as`** and **`track by`**
36308  *
36309  * <div class="alert alert-warning">
36310  * Be careful when using `select` **`as`** and **`track by`** in the same expression.
36311  * </div>
36312  *
36313  * Given this array of items on the $scope:
36314  *
36315  * ```js
36316  * $scope.items = [{
36317  *   id: 1,
36318  *   label: 'aLabel',
36319  *   subItem: { name: 'aSubItem' }
36320  * }, {
36321  *   id: 2,
36322  *   label: 'bLabel',
36323  *   subItem: { name: 'bSubItem' }
36324  * }];
36325  * ```
36326  *
36327  * This will work:
36328  *
36329  * ```html
36330  * <select ng-options="item as item.label for item in items track by item.id" ng-model="selected"></select>
36331  * ```
36332  * ```js
36333  * $scope.selected = $scope.items[0];
36334  * ```
36335  *
36336  * but this will not work:
36337  *
36338  * ```html
36339  * <select ng-options="item.subItem as item.label for item in items track by item.id" ng-model="selected"></select>
36340  * ```
36341  * ```js
36342  * $scope.selected = $scope.items[0].subItem;
36343  * ```
36344  *
36345  * In both examples, the **`track by`** expression is applied successfully to each `item` in the
36346  * `items` array. Because the selected option has been set programmatically in the controller, the
36347  * **`track by`** expression is also applied to the `ngModel` value. In the first example, the
36348  * `ngModel` value is `items[0]` and the **`track by`** expression evaluates to `items[0].id` with
36349  * no issue. In the second example, the `ngModel` value is `items[0].subItem` and the **`track by`**
36350  * expression evaluates to `items[0].subItem.id` (which is undefined). As a result, the model value
36351  * is not matched against any `<option>` and the `<select>` appears as having no selected value.
36352  *
36353  *
36354  * @param {string} ngModel Assignable angular expression to data-bind to.
36355  * @param {string=} name Property name of the form under which the control is published.
36356  * @param {string=} required The control is considered valid only if value is entered.
36357  * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
36358  *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
36359  *    `required` when you want to data-bind to the `required` attribute.
36360  * @param {comprehension_expression=} ngOptions in one of the following forms:
36361  *
36362  *   * for array data sources:
36363  *     * `label` **`for`** `value` **`in`** `array`
36364  *     * `select` **`as`** `label` **`for`** `value` **`in`** `array`
36365  *     * `label` **`group by`** `group` **`for`** `value` **`in`** `array`
36366  *     * `label` **`disable when`** `disable` **`for`** `value` **`in`** `array`
36367  *     * `label` **`group by`** `group` **`for`** `value` **`in`** `array` **`track by`** `trackexpr`
36368  *     * `label` **`disable when`** `disable` **`for`** `value` **`in`** `array` **`track by`** `trackexpr`
36369  *     * `label` **`for`** `value` **`in`** `array` | orderBy:`orderexpr` **`track by`** `trackexpr`
36370  *        (for including a filter with `track by`)
36371  *   * for object data sources:
36372  *     * `label` **`for (`**`key` **`,`** `value`**`) in`** `object`
36373  *     * `select` **`as`** `label` **`for (`**`key` **`,`** `value`**`) in`** `object`
36374  *     * `label` **`group by`** `group` **`for (`**`key`**`,`** `value`**`) in`** `object`
36375  *     * `label` **`disable when`** `disable` **`for (`**`key`**`,`** `value`**`) in`** `object`
36376  *     * `select` **`as`** `label` **`group by`** `group`
36377  *         **`for` `(`**`key`**`,`** `value`**`) in`** `object`
36378  *     * `select` **`as`** `label` **`disable when`** `disable`
36379  *         **`for` `(`**`key`**`,`** `value`**`) in`** `object`
36380  *
36381  * Where:
36382  *
36383  *   * `array` / `object`: an expression which evaluates to an array / object to iterate over.
36384  *   * `value`: local variable which will refer to each item in the `array` or each property value
36385  *      of `object` during iteration.
36386  *   * `key`: local variable which will refer to a property name in `object` during iteration.
36387  *   * `label`: The result of this expression will be the label for `<option>` element. The
36388  *     `expression` will most likely refer to the `value` variable (e.g. `value.propertyName`).
36389  *   * `select`: The result of this expression will be bound to the model of the parent `<select>`
36390  *      element. If not specified, `select` expression will default to `value`.
36391  *   * `group`: The result of this expression will be used to group options using the `<optgroup>`
36392  *      DOM element.
36393  *   * `disable`: The result of this expression will be used to disable the rendered `<option>`
36394  *      element. Return `true` to disable.
36395  *   * `trackexpr`: Used when working with an array of objects. The result of this expression will be
36396  *      used to identify the objects in the array. The `trackexpr` will most likely refer to the
36397  *     `value` variable (e.g. `value.propertyName`). With this the selection is preserved
36398  *      even when the options are recreated (e.g. reloaded from the server).
36399  *
36400  * @example
36401     <example module="selectExample">
36402       <file name="index.html">
36403         <script>
36404         angular.module('selectExample', [])
36405           .controller('ExampleController', ['$scope', function($scope) {
36406             $scope.colors = [
36407               {name:'black', shade:'dark'},
36408               {name:'white', shade:'light', notAnOption: true},
36409               {name:'red', shade:'dark'},
36410               {name:'blue', shade:'dark', notAnOption: true},
36411               {name:'yellow', shade:'light', notAnOption: false}
36412             ];
36413             $scope.myColor = $scope.colors[2]; // red
36414           }]);
36415         </script>
36416         <div ng-controller="ExampleController">
36417           <ul>
36418             <li ng-repeat="color in colors">
36419               <label>Name: <input ng-model="color.name"></label>
36420               <label><input type="checkbox" ng-model="color.notAnOption"> Disabled?</label>
36421               <button ng-click="colors.splice($index, 1)" aria-label="Remove">X</button>
36422             </li>
36423             <li>
36424               <button ng-click="colors.push({})">add</button>
36425             </li>
36426           </ul>
36427           <hr/>
36428           <label>Color (null not allowed):
36429             <select ng-model="myColor" ng-options="color.name for color in colors"></select>
36430           </label><br/>
36431           <label>Color (null allowed):
36432           <span  class="nullable">
36433             <select ng-model="myColor" ng-options="color.name for color in colors">
36434               <option value="">-- choose color --</option>
36435             </select>
36436           </span></label><br/>
36437
36438           <label>Color grouped by shade:
36439             <select ng-model="myColor" ng-options="color.name group by color.shade for color in colors">
36440             </select>
36441           </label><br/>
36442
36443           <label>Color grouped by shade, with some disabled:
36444             <select ng-model="myColor"
36445                   ng-options="color.name group by color.shade disable when color.notAnOption for color in colors">
36446             </select>
36447           </label><br/>
36448
36449
36450
36451           Select <button ng-click="myColor = { name:'not in list', shade: 'other' }">bogus</button>.
36452           <br/>
36453           <hr/>
36454           Currently selected: {{ {selected_color:myColor} }}
36455           <div style="border:solid 1px black; height:20px"
36456                ng-style="{'background-color':myColor.name}">
36457           </div>
36458         </div>
36459       </file>
36460       <file name="protractor.js" type="protractor">
36461          it('should check ng-options', function() {
36462            expect(element(by.binding('{selected_color:myColor}')).getText()).toMatch('red');
36463            element.all(by.model('myColor')).first().click();
36464            element.all(by.css('select[ng-model="myColor"] option')).first().click();
36465            expect(element(by.binding('{selected_color:myColor}')).getText()).toMatch('black');
36466            element(by.css('.nullable select[ng-model="myColor"]')).click();
36467            element.all(by.css('.nullable select[ng-model="myColor"] option')).first().click();
36468            expect(element(by.binding('{selected_color:myColor}')).getText()).toMatch('null');
36469          });
36470       </file>
36471     </example>
36472  */
36473
36474 // jshint maxlen: false
36475 //                     //00001111111111000000000002222222222000000000000000000000333333333300000000000000000000000004444444444400000000000005555555555555550000000006666666666666660000000777777777777777000000000000000888888888800000000000000000009999999999
36476 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]+?))?$/;
36477                         // 1: value expression (valueFn)
36478                         // 2: label expression (displayFn)
36479                         // 3: group by expression (groupByFn)
36480                         // 4: disable when expression (disableWhenFn)
36481                         // 5: array item variable name
36482                         // 6: object item key variable name
36483                         // 7: object item value variable name
36484                         // 8: collection expression
36485                         // 9: track by expression
36486 // jshint maxlen: 100
36487
36488
36489 var ngOptionsDirective = ['$compile', '$parse', function($compile, $parse) {
36490
36491   function parseOptionsExpression(optionsExp, selectElement, scope) {
36492
36493     var match = optionsExp.match(NG_OPTIONS_REGEXP);
36494     if (!(match)) {
36495       throw ngOptionsMinErr('iexp',
36496         "Expected expression in form of " +
36497         "'_select_ (as _label_)? for (_key_,)?_value_ in _collection_'" +
36498         " but got '{0}'. Element: {1}",
36499         optionsExp, startingTag(selectElement));
36500     }
36501
36502     // Extract the parts from the ngOptions expression
36503
36504     // The variable name for the value of the item in the collection
36505     var valueName = match[5] || match[7];
36506     // The variable name for the key of the item in the collection
36507     var keyName = match[6];
36508
36509     // An expression that generates the viewValue for an option if there is a label expression
36510     var selectAs = / as /.test(match[0]) && match[1];
36511     // An expression that is used to track the id of each object in the options collection
36512     var trackBy = match[9];
36513     // An expression that generates the viewValue for an option if there is no label expression
36514     var valueFn = $parse(match[2] ? match[1] : valueName);
36515     var selectAsFn = selectAs && $parse(selectAs);
36516     var viewValueFn = selectAsFn || valueFn;
36517     var trackByFn = trackBy && $parse(trackBy);
36518
36519     // Get the value by which we are going to track the option
36520     // if we have a trackFn then use that (passing scope and locals)
36521     // otherwise just hash the given viewValue
36522     var getTrackByValueFn = trackBy ?
36523                               function(value, locals) { return trackByFn(scope, locals); } :
36524                               function getHashOfValue(value) { return hashKey(value); };
36525     var getTrackByValue = function(value, key) {
36526       return getTrackByValueFn(value, getLocals(value, key));
36527     };
36528
36529     var displayFn = $parse(match[2] || match[1]);
36530     var groupByFn = $parse(match[3] || '');
36531     var disableWhenFn = $parse(match[4] || '');
36532     var valuesFn = $parse(match[8]);
36533
36534     var locals = {};
36535     var getLocals = keyName ? function(value, key) {
36536       locals[keyName] = key;
36537       locals[valueName] = value;
36538       return locals;
36539     } : function(value) {
36540       locals[valueName] = value;
36541       return locals;
36542     };
36543
36544
36545     function Option(selectValue, viewValue, label, group, disabled) {
36546       this.selectValue = selectValue;
36547       this.viewValue = viewValue;
36548       this.label = label;
36549       this.group = group;
36550       this.disabled = disabled;
36551     }
36552
36553     function getOptionValuesKeys(optionValues) {
36554       var optionValuesKeys;
36555
36556       if (!keyName && isArrayLike(optionValues)) {
36557         optionValuesKeys = optionValues;
36558       } else {
36559         // if object, extract keys, in enumeration order, unsorted
36560         optionValuesKeys = [];
36561         for (var itemKey in optionValues) {
36562           if (optionValues.hasOwnProperty(itemKey) && itemKey.charAt(0) !== '$') {
36563             optionValuesKeys.push(itemKey);
36564           }
36565         }
36566       }
36567       return optionValuesKeys;
36568     }
36569
36570     return {
36571       trackBy: trackBy,
36572       getTrackByValue: getTrackByValue,
36573       getWatchables: $parse(valuesFn, function(optionValues) {
36574         // Create a collection of things that we would like to watch (watchedArray)
36575         // so that they can all be watched using a single $watchCollection
36576         // that only runs the handler once if anything changes
36577         var watchedArray = [];
36578         optionValues = optionValues || [];
36579
36580         var optionValuesKeys = getOptionValuesKeys(optionValues);
36581         var optionValuesLength = optionValuesKeys.length;
36582         for (var index = 0; index < optionValuesLength; index++) {
36583           var key = (optionValues === optionValuesKeys) ? index : optionValuesKeys[index];
36584           var value = optionValues[key];
36585
36586           var locals = getLocals(optionValues[key], key);
36587           var selectValue = getTrackByValueFn(optionValues[key], locals);
36588           watchedArray.push(selectValue);
36589
36590           // Only need to watch the displayFn if there is a specific label expression
36591           if (match[2] || match[1]) {
36592             var label = displayFn(scope, locals);
36593             watchedArray.push(label);
36594           }
36595
36596           // Only need to watch the disableWhenFn if there is a specific disable expression
36597           if (match[4]) {
36598             var disableWhen = disableWhenFn(scope, locals);
36599             watchedArray.push(disableWhen);
36600           }
36601         }
36602         return watchedArray;
36603       }),
36604
36605       getOptions: function() {
36606
36607         var optionItems = [];
36608         var selectValueMap = {};
36609
36610         // The option values were already computed in the `getWatchables` fn,
36611         // which must have been called to trigger `getOptions`
36612         var optionValues = valuesFn(scope) || [];
36613         var optionValuesKeys = getOptionValuesKeys(optionValues);
36614         var optionValuesLength = optionValuesKeys.length;
36615
36616         for (var index = 0; index < optionValuesLength; index++) {
36617           var key = (optionValues === optionValuesKeys) ? index : optionValuesKeys[index];
36618           var value = optionValues[key];
36619           var locals = getLocals(value, key);
36620           var viewValue = viewValueFn(scope, locals);
36621           var selectValue = getTrackByValueFn(viewValue, locals);
36622           var label = displayFn(scope, locals);
36623           var group = groupByFn(scope, locals);
36624           var disabled = disableWhenFn(scope, locals);
36625           var optionItem = new Option(selectValue, viewValue, label, group, disabled);
36626
36627           optionItems.push(optionItem);
36628           selectValueMap[selectValue] = optionItem;
36629         }
36630
36631         return {
36632           items: optionItems,
36633           selectValueMap: selectValueMap,
36634           getOptionFromViewValue: function(value) {
36635             return selectValueMap[getTrackByValue(value)];
36636           },
36637           getViewValueFromOption: function(option) {
36638             // If the viewValue could be an object that may be mutated by the application,
36639             // we need to make a copy and not return the reference to the value on the option.
36640             return trackBy ? angular.copy(option.viewValue) : option.viewValue;
36641           }
36642         };
36643       }
36644     };
36645   }
36646
36647
36648   // we can't just jqLite('<option>') since jqLite is not smart enough
36649   // to create it in <select> and IE barfs otherwise.
36650   var optionTemplate = document.createElement('option'),
36651       optGroupTemplate = document.createElement('optgroup');
36652
36653     function ngOptionsPostLink(scope, selectElement, attr, ctrls) {
36654
36655       var selectCtrl = ctrls[0];
36656       var ngModelCtrl = ctrls[1];
36657       var multiple = attr.multiple;
36658
36659       // The emptyOption allows the application developer to provide their own custom "empty"
36660       // option when the viewValue does not match any of the option values.
36661       var emptyOption;
36662       for (var i = 0, children = selectElement.children(), ii = children.length; i < ii; i++) {
36663         if (children[i].value === '') {
36664           emptyOption = children.eq(i);
36665           break;
36666         }
36667       }
36668
36669       var providedEmptyOption = !!emptyOption;
36670
36671       var unknownOption = jqLite(optionTemplate.cloneNode(false));
36672       unknownOption.val('?');
36673
36674       var options;
36675       var ngOptions = parseOptionsExpression(attr.ngOptions, selectElement, scope);
36676
36677
36678       var renderEmptyOption = function() {
36679         if (!providedEmptyOption) {
36680           selectElement.prepend(emptyOption);
36681         }
36682         selectElement.val('');
36683         emptyOption.prop('selected', true); // needed for IE
36684         emptyOption.attr('selected', true);
36685       };
36686
36687       var removeEmptyOption = function() {
36688         if (!providedEmptyOption) {
36689           emptyOption.remove();
36690         }
36691       };
36692
36693
36694       var renderUnknownOption = function() {
36695         selectElement.prepend(unknownOption);
36696         selectElement.val('?');
36697         unknownOption.prop('selected', true); // needed for IE
36698         unknownOption.attr('selected', true);
36699       };
36700
36701       var removeUnknownOption = function() {
36702         unknownOption.remove();
36703       };
36704
36705       // Update the controller methods for multiple selectable options
36706       if (!multiple) {
36707
36708         selectCtrl.writeValue = function writeNgOptionsValue(value) {
36709           var option = options.getOptionFromViewValue(value);
36710
36711           if (option && !option.disabled) {
36712             if (selectElement[0].value !== option.selectValue) {
36713               removeUnknownOption();
36714               removeEmptyOption();
36715
36716               selectElement[0].value = option.selectValue;
36717               option.element.selected = true;
36718               option.element.setAttribute('selected', 'selected');
36719             }
36720           } else {
36721             if (value === null || providedEmptyOption) {
36722               removeUnknownOption();
36723               renderEmptyOption();
36724             } else {
36725               removeEmptyOption();
36726               renderUnknownOption();
36727             }
36728           }
36729         };
36730
36731         selectCtrl.readValue = function readNgOptionsValue() {
36732
36733           var selectedOption = options.selectValueMap[selectElement.val()];
36734
36735           if (selectedOption && !selectedOption.disabled) {
36736             removeEmptyOption();
36737             removeUnknownOption();
36738             return options.getViewValueFromOption(selectedOption);
36739           }
36740           return null;
36741         };
36742
36743         // If we are using `track by` then we must watch the tracked value on the model
36744         // since ngModel only watches for object identity change
36745         if (ngOptions.trackBy) {
36746           scope.$watch(
36747             function() { return ngOptions.getTrackByValue(ngModelCtrl.$viewValue); },
36748             function() { ngModelCtrl.$render(); }
36749           );
36750         }
36751
36752       } else {
36753
36754         ngModelCtrl.$isEmpty = function(value) {
36755           return !value || value.length === 0;
36756         };
36757
36758
36759         selectCtrl.writeValue = function writeNgOptionsMultiple(value) {
36760           options.items.forEach(function(option) {
36761             option.element.selected = false;
36762           });
36763
36764           if (value) {
36765             value.forEach(function(item) {
36766               var option = options.getOptionFromViewValue(item);
36767               if (option && !option.disabled) option.element.selected = true;
36768             });
36769           }
36770         };
36771
36772
36773         selectCtrl.readValue = function readNgOptionsMultiple() {
36774           var selectedValues = selectElement.val() || [],
36775               selections = [];
36776
36777           forEach(selectedValues, function(value) {
36778             var option = options.selectValueMap[value];
36779             if (option && !option.disabled) selections.push(options.getViewValueFromOption(option));
36780           });
36781
36782           return selections;
36783         };
36784
36785         // If we are using `track by` then we must watch these tracked values on the model
36786         // since ngModel only watches for object identity change
36787         if (ngOptions.trackBy) {
36788
36789           scope.$watchCollection(function() {
36790             if (isArray(ngModelCtrl.$viewValue)) {
36791               return ngModelCtrl.$viewValue.map(function(value) {
36792                 return ngOptions.getTrackByValue(value);
36793               });
36794             }
36795           }, function() {
36796             ngModelCtrl.$render();
36797           });
36798
36799         }
36800       }
36801
36802
36803       if (providedEmptyOption) {
36804
36805         // we need to remove it before calling selectElement.empty() because otherwise IE will
36806         // remove the label from the element. wtf?
36807         emptyOption.remove();
36808
36809         // compile the element since there might be bindings in it
36810         $compile(emptyOption)(scope);
36811
36812         // remove the class, which is added automatically because we recompile the element and it
36813         // becomes the compilation root
36814         emptyOption.removeClass('ng-scope');
36815       } else {
36816         emptyOption = jqLite(optionTemplate.cloneNode(false));
36817       }
36818
36819       // We need to do this here to ensure that the options object is defined
36820       // when we first hit it in writeNgOptionsValue
36821       updateOptions();
36822
36823       // We will re-render the option elements if the option values or labels change
36824       scope.$watchCollection(ngOptions.getWatchables, updateOptions);
36825
36826       // ------------------------------------------------------------------ //
36827
36828
36829       function updateOptionElement(option, element) {
36830         option.element = element;
36831         element.disabled = option.disabled;
36832         // NOTE: The label must be set before the value, otherwise IE10/11/EDGE create unresponsive
36833         // selects in certain circumstances when multiple selects are next to each other and display
36834         // the option list in listbox style, i.e. the select is [multiple], or specifies a [size].
36835         // See https://github.com/angular/angular.js/issues/11314 for more info.
36836         // This is unfortunately untestable with unit / e2e tests
36837         if (option.label !== element.label) {
36838           element.label = option.label;
36839           element.textContent = option.label;
36840         }
36841         if (option.value !== element.value) element.value = option.selectValue;
36842       }
36843
36844       function addOrReuseElement(parent, current, type, templateElement) {
36845         var element;
36846         // Check whether we can reuse the next element
36847         if (current && lowercase(current.nodeName) === type) {
36848           // The next element is the right type so reuse it
36849           element = current;
36850         } else {
36851           // The next element is not the right type so create a new one
36852           element = templateElement.cloneNode(false);
36853           if (!current) {
36854             // There are no more elements so just append it to the select
36855             parent.appendChild(element);
36856           } else {
36857             // The next element is not a group so insert the new one
36858             parent.insertBefore(element, current);
36859           }
36860         }
36861         return element;
36862       }
36863
36864
36865       function removeExcessElements(current) {
36866         var next;
36867         while (current) {
36868           next = current.nextSibling;
36869           jqLiteRemove(current);
36870           current = next;
36871         }
36872       }
36873
36874
36875       function skipEmptyAndUnknownOptions(current) {
36876         var emptyOption_ = emptyOption && emptyOption[0];
36877         var unknownOption_ = unknownOption && unknownOption[0];
36878
36879         // We cannot rely on the extracted empty option being the same as the compiled empty option,
36880         // because the compiled empty option might have been replaced by a comment because
36881         // it had an "element" transclusion directive on it (such as ngIf)
36882         if (emptyOption_ || unknownOption_) {
36883           while (current &&
36884                 (current === emptyOption_ ||
36885                 current === unknownOption_ ||
36886                 current.nodeType === NODE_TYPE_COMMENT ||
36887                 (nodeName_(current) === 'option' && current.value === ''))) {
36888             current = current.nextSibling;
36889           }
36890         }
36891         return current;
36892       }
36893
36894
36895       function updateOptions() {
36896
36897         var previousValue = options && selectCtrl.readValue();
36898
36899         options = ngOptions.getOptions();
36900
36901         var groupMap = {};
36902         var currentElement = selectElement[0].firstChild;
36903
36904         // Ensure that the empty option is always there if it was explicitly provided
36905         if (providedEmptyOption) {
36906           selectElement.prepend(emptyOption);
36907         }
36908
36909         currentElement = skipEmptyAndUnknownOptions(currentElement);
36910
36911         options.items.forEach(function updateOption(option) {
36912           var group;
36913           var groupElement;
36914           var optionElement;
36915
36916           if (isDefined(option.group)) {
36917
36918             // This option is to live in a group
36919             // See if we have already created this group
36920             group = groupMap[option.group];
36921
36922             if (!group) {
36923
36924               // We have not already created this group
36925               groupElement = addOrReuseElement(selectElement[0],
36926                                                currentElement,
36927                                                'optgroup',
36928                                                optGroupTemplate);
36929               // Move to the next element
36930               currentElement = groupElement.nextSibling;
36931
36932               // Update the label on the group element
36933               groupElement.label = option.group;
36934
36935               // Store it for use later
36936               group = groupMap[option.group] = {
36937                 groupElement: groupElement,
36938                 currentOptionElement: groupElement.firstChild
36939               };
36940
36941             }
36942
36943             // So now we have a group for this option we add the option to the group
36944             optionElement = addOrReuseElement(group.groupElement,
36945                                               group.currentOptionElement,
36946                                               'option',
36947                                               optionTemplate);
36948             updateOptionElement(option, optionElement);
36949             // Move to the next element
36950             group.currentOptionElement = optionElement.nextSibling;
36951
36952           } else {
36953
36954             // This option is not in a group
36955             optionElement = addOrReuseElement(selectElement[0],
36956                                               currentElement,
36957                                               'option',
36958                                               optionTemplate);
36959             updateOptionElement(option, optionElement);
36960             // Move to the next element
36961             currentElement = optionElement.nextSibling;
36962           }
36963         });
36964
36965
36966         // Now remove all excess options and group
36967         Object.keys(groupMap).forEach(function(key) {
36968           removeExcessElements(groupMap[key].currentOptionElement);
36969         });
36970         removeExcessElements(currentElement);
36971
36972         ngModelCtrl.$render();
36973
36974         // Check to see if the value has changed due to the update to the options
36975         if (!ngModelCtrl.$isEmpty(previousValue)) {
36976           var nextValue = selectCtrl.readValue();
36977           var isNotPrimitive = ngOptions.trackBy || multiple;
36978           if (isNotPrimitive ? !equals(previousValue, nextValue) : previousValue !== nextValue) {
36979             ngModelCtrl.$setViewValue(nextValue);
36980             ngModelCtrl.$render();
36981           }
36982         }
36983
36984       }
36985   }
36986
36987   return {
36988     restrict: 'A',
36989     terminal: true,
36990     require: ['select', 'ngModel'],
36991     link: {
36992       pre: function ngOptionsPreLink(scope, selectElement, attr, ctrls) {
36993         // Deactivate the SelectController.register method to prevent
36994         // option directives from accidentally registering themselves
36995         // (and unwanted $destroy handlers etc.)
36996         ctrls[0].registerOption = noop;
36997       },
36998       post: ngOptionsPostLink
36999     }
37000   };
37001 }];
37002
37003 /**
37004  * @ngdoc directive
37005  * @name ngPluralize
37006  * @restrict EA
37007  *
37008  * @description
37009  * `ngPluralize` is a directive that displays messages according to en-US localization rules.
37010  * These rules are bundled with angular.js, but can be overridden
37011  * (see {@link guide/i18n Angular i18n} dev guide). You configure ngPluralize directive
37012  * by specifying the mappings between
37013  * [plural categories](http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html)
37014  * and the strings to be displayed.
37015  *
37016  * # Plural categories and explicit number rules
37017  * There are two
37018  * [plural categories](http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html)
37019  * in Angular's default en-US locale: "one" and "other".
37020  *
37021  * While a plural category may match many numbers (for example, in en-US locale, "other" can match
37022  * any number that is not 1), an explicit number rule can only match one number. For example, the
37023  * explicit number rule for "3" matches the number 3. There are examples of plural categories
37024  * and explicit number rules throughout the rest of this documentation.
37025  *
37026  * # Configuring ngPluralize
37027  * You configure ngPluralize by providing 2 attributes: `count` and `when`.
37028  * You can also provide an optional attribute, `offset`.
37029  *
37030  * The value of the `count` attribute can be either a string or an {@link guide/expression
37031  * Angular expression}; these are evaluated on the current scope for its bound value.
37032  *
37033  * The `when` attribute specifies the mappings between plural categories and the actual
37034  * string to be displayed. The value of the attribute should be a JSON object.
37035  *
37036  * The following example shows how to configure ngPluralize:
37037  *
37038  * ```html
37039  * <ng-pluralize count="personCount"
37040                  when="{'0': 'Nobody is viewing.',
37041  *                      'one': '1 person is viewing.',
37042  *                      'other': '{} people are viewing.'}">
37043  * </ng-pluralize>
37044  *```
37045  *
37046  * In the example, `"0: Nobody is viewing."` is an explicit number rule. If you did not
37047  * specify this rule, 0 would be matched to the "other" category and "0 people are viewing"
37048  * would be shown instead of "Nobody is viewing". You can specify an explicit number rule for
37049  * other numbers, for example 12, so that instead of showing "12 people are viewing", you can
37050  * show "a dozen people are viewing".
37051  *
37052  * You can use a set of closed braces (`{}`) as a placeholder for the number that you want substituted
37053  * into pluralized strings. In the previous example, Angular will replace `{}` with
37054  * <span ng-non-bindable>`{{personCount}}`</span>. The closed braces `{}` is a placeholder
37055  * for <span ng-non-bindable>{{numberExpression}}</span>.
37056  *
37057  * If no rule is defined for a category, then an empty string is displayed and a warning is generated.
37058  * Note that some locales define more categories than `one` and `other`. For example, fr-fr defines `few` and `many`.
37059  *
37060  * # Configuring ngPluralize with offset
37061  * The `offset` attribute allows further customization of pluralized text, which can result in
37062  * a better user experience. For example, instead of the message "4 people are viewing this document",
37063  * you might display "John, Kate and 2 others are viewing this document".
37064  * The offset attribute allows you to offset a number by any desired value.
37065  * Let's take a look at an example:
37066  *
37067  * ```html
37068  * <ng-pluralize count="personCount" offset=2
37069  *               when="{'0': 'Nobody is viewing.',
37070  *                      '1': '{{person1}} is viewing.',
37071  *                      '2': '{{person1}} and {{person2}} are viewing.',
37072  *                      'one': '{{person1}}, {{person2}} and one other person are viewing.',
37073  *                      'other': '{{person1}}, {{person2}} and {} other people are viewing.'}">
37074  * </ng-pluralize>
37075  * ```
37076  *
37077  * Notice that we are still using two plural categories(one, other), but we added
37078  * three explicit number rules 0, 1 and 2.
37079  * When one person, perhaps John, views the document, "John is viewing" will be shown.
37080  * When three people view the document, no explicit number rule is found, so
37081  * an offset of 2 is taken off 3, and Angular uses 1 to decide the plural category.
37082  * In this case, plural category 'one' is matched and "John, Mary and one other person are viewing"
37083  * is shown.
37084  *
37085  * Note that when you specify offsets, you must provide explicit number rules for
37086  * numbers from 0 up to and including the offset. If you use an offset of 3, for example,
37087  * you must provide explicit number rules for 0, 1, 2 and 3. You must also provide plural strings for
37088  * plural categories "one" and "other".
37089  *
37090  * @param {string|expression} count The variable to be bound to.
37091  * @param {string} when The mapping between plural category to its corresponding strings.
37092  * @param {number=} offset Offset to deduct from the total number.
37093  *
37094  * @example
37095     <example module="pluralizeExample">
37096       <file name="index.html">
37097         <script>
37098           angular.module('pluralizeExample', [])
37099             .controller('ExampleController', ['$scope', function($scope) {
37100               $scope.person1 = 'Igor';
37101               $scope.person2 = 'Misko';
37102               $scope.personCount = 1;
37103             }]);
37104         </script>
37105         <div ng-controller="ExampleController">
37106           <label>Person 1:<input type="text" ng-model="person1" value="Igor" /></label><br/>
37107           <label>Person 2:<input type="text" ng-model="person2" value="Misko" /></label><br/>
37108           <label>Number of People:<input type="text" ng-model="personCount" value="1" /></label><br/>
37109
37110           <!--- Example with simple pluralization rules for en locale --->
37111           Without Offset:
37112           <ng-pluralize count="personCount"
37113                         when="{'0': 'Nobody is viewing.',
37114                                'one': '1 person is viewing.',
37115                                'other': '{} people are viewing.'}">
37116           </ng-pluralize><br>
37117
37118           <!--- Example with offset --->
37119           With Offset(2):
37120           <ng-pluralize count="personCount" offset=2
37121                         when="{'0': 'Nobody is viewing.',
37122                                '1': '{{person1}} is viewing.',
37123                                '2': '{{person1}} and {{person2}} are viewing.',
37124                                'one': '{{person1}}, {{person2}} and one other person are viewing.',
37125                                'other': '{{person1}}, {{person2}} and {} other people are viewing.'}">
37126           </ng-pluralize>
37127         </div>
37128       </file>
37129       <file name="protractor.js" type="protractor">
37130         it('should show correct pluralized string', function() {
37131           var withoutOffset = element.all(by.css('ng-pluralize')).get(0);
37132           var withOffset = element.all(by.css('ng-pluralize')).get(1);
37133           var countInput = element(by.model('personCount'));
37134
37135           expect(withoutOffset.getText()).toEqual('1 person is viewing.');
37136           expect(withOffset.getText()).toEqual('Igor is viewing.');
37137
37138           countInput.clear();
37139           countInput.sendKeys('0');
37140
37141           expect(withoutOffset.getText()).toEqual('Nobody is viewing.');
37142           expect(withOffset.getText()).toEqual('Nobody is viewing.');
37143
37144           countInput.clear();
37145           countInput.sendKeys('2');
37146
37147           expect(withoutOffset.getText()).toEqual('2 people are viewing.');
37148           expect(withOffset.getText()).toEqual('Igor and Misko are viewing.');
37149
37150           countInput.clear();
37151           countInput.sendKeys('3');
37152
37153           expect(withoutOffset.getText()).toEqual('3 people are viewing.');
37154           expect(withOffset.getText()).toEqual('Igor, Misko and one other person are viewing.');
37155
37156           countInput.clear();
37157           countInput.sendKeys('4');
37158
37159           expect(withoutOffset.getText()).toEqual('4 people are viewing.');
37160           expect(withOffset.getText()).toEqual('Igor, Misko and 2 other people are viewing.');
37161         });
37162         it('should show data-bound names', function() {
37163           var withOffset = element.all(by.css('ng-pluralize')).get(1);
37164           var personCount = element(by.model('personCount'));
37165           var person1 = element(by.model('person1'));
37166           var person2 = element(by.model('person2'));
37167           personCount.clear();
37168           personCount.sendKeys('4');
37169           person1.clear();
37170           person1.sendKeys('Di');
37171           person2.clear();
37172           person2.sendKeys('Vojta');
37173           expect(withOffset.getText()).toEqual('Di, Vojta and 2 other people are viewing.');
37174         });
37175       </file>
37176     </example>
37177  */
37178 var ngPluralizeDirective = ['$locale', '$interpolate', '$log', function($locale, $interpolate, $log) {
37179   var BRACE = /{}/g,
37180       IS_WHEN = /^when(Minus)?(.+)$/;
37181
37182   return {
37183     link: function(scope, element, attr) {
37184       var numberExp = attr.count,
37185           whenExp = attr.$attr.when && element.attr(attr.$attr.when), // we have {{}} in attrs
37186           offset = attr.offset || 0,
37187           whens = scope.$eval(whenExp) || {},
37188           whensExpFns = {},
37189           startSymbol = $interpolate.startSymbol(),
37190           endSymbol = $interpolate.endSymbol(),
37191           braceReplacement = startSymbol + numberExp + '-' + offset + endSymbol,
37192           watchRemover = angular.noop,
37193           lastCount;
37194
37195       forEach(attr, function(expression, attributeName) {
37196         var tmpMatch = IS_WHEN.exec(attributeName);
37197         if (tmpMatch) {
37198           var whenKey = (tmpMatch[1] ? '-' : '') + lowercase(tmpMatch[2]);
37199           whens[whenKey] = element.attr(attr.$attr[attributeName]);
37200         }
37201       });
37202       forEach(whens, function(expression, key) {
37203         whensExpFns[key] = $interpolate(expression.replace(BRACE, braceReplacement));
37204
37205       });
37206
37207       scope.$watch(numberExp, function ngPluralizeWatchAction(newVal) {
37208         var count = parseFloat(newVal);
37209         var countIsNaN = isNaN(count);
37210
37211         if (!countIsNaN && !(count in whens)) {
37212           // If an explicit number rule such as 1, 2, 3... is defined, just use it.
37213           // Otherwise, check it against pluralization rules in $locale service.
37214           count = $locale.pluralCat(count - offset);
37215         }
37216
37217         // If both `count` and `lastCount` are NaN, we don't need to re-register a watch.
37218         // In JS `NaN !== NaN`, so we have to explicitly check.
37219         if ((count !== lastCount) && !(countIsNaN && isNumber(lastCount) && isNaN(lastCount))) {
37220           watchRemover();
37221           var whenExpFn = whensExpFns[count];
37222           if (isUndefined(whenExpFn)) {
37223             if (newVal != null) {
37224               $log.debug("ngPluralize: no rule defined for '" + count + "' in " + whenExp);
37225             }
37226             watchRemover = noop;
37227             updateElementText();
37228           } else {
37229             watchRemover = scope.$watch(whenExpFn, updateElementText);
37230           }
37231           lastCount = count;
37232         }
37233       });
37234
37235       function updateElementText(newText) {
37236         element.text(newText || '');
37237       }
37238     }
37239   };
37240 }];
37241
37242 /**
37243  * @ngdoc directive
37244  * @name ngRepeat
37245  * @multiElement
37246  *
37247  * @description
37248  * The `ngRepeat` directive instantiates a template once per item from a collection. Each template
37249  * instance gets its own scope, where the given loop variable is set to the current collection item,
37250  * and `$index` is set to the item index or key.
37251  *
37252  * Special properties are exposed on the local scope of each template instance, including:
37253  *
37254  * | Variable  | Type            | Details                                                                     |
37255  * |-----------|-----------------|-----------------------------------------------------------------------------|
37256  * | `$index`  | {@type number}  | iterator offset of the repeated element (0..length-1)                       |
37257  * | `$first`  | {@type boolean} | true if the repeated element is first in the iterator.                      |
37258  * | `$middle` | {@type boolean} | true if the repeated element is between the first and last in the iterator. |
37259  * | `$last`   | {@type boolean} | true if the repeated element is last in the iterator.                       |
37260  * | `$even`   | {@type boolean} | true if the iterator position `$index` is even (otherwise false).           |
37261  * | `$odd`    | {@type boolean} | true if the iterator position `$index` is odd (otherwise false).            |
37262  *
37263  * <div class="alert alert-info">
37264  *   Creating aliases for these properties is possible with {@link ng.directive:ngInit `ngInit`}.
37265  *   This may be useful when, for instance, nesting ngRepeats.
37266  * </div>
37267  *
37268  *
37269  * # Iterating over object properties
37270  *
37271  * It is possible to get `ngRepeat` to iterate over the properties of an object using the following
37272  * syntax:
37273  *
37274  * ```js
37275  * <div ng-repeat="(key, value) in myObj"> ... </div>
37276  * ```
37277  *
37278  * You need to be aware that the JavaScript specification does not define the order of keys
37279  * returned for an object. (To mitigate this in Angular 1.3 the `ngRepeat` directive
37280  * used to sort the keys alphabetically.)
37281  *
37282  * Version 1.4 removed the alphabetic sorting. We now rely on the order returned by the browser
37283  * when running `for key in myObj`. It seems that browsers generally follow the strategy of providing
37284  * keys in the order in which they were defined, although there are exceptions when keys are deleted
37285  * and reinstated. See the [MDN page on `delete` for more info](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/delete#Cross-browser_notes).
37286  *
37287  * If this is not desired, the recommended workaround is to convert your object into an array
37288  * that is sorted into the order that you prefer before providing it to `ngRepeat`.  You could
37289  * do this with a filter such as [toArrayFilter](http://ngmodules.org/modules/angular-toArrayFilter)
37290  * or implement a `$watch` on the object yourself.
37291  *
37292  *
37293  * # Tracking and Duplicates
37294  *
37295  * `ngRepeat` uses {@link $rootScope.Scope#$watchCollection $watchCollection} to detect changes in
37296  * the collection. When a change happens, ngRepeat then makes the corresponding changes to the DOM:
37297  *
37298  * * When an item is added, a new instance of the template is added to the DOM.
37299  * * When an item is removed, its template instance is removed from the DOM.
37300  * * When items are reordered, their respective templates are reordered in the DOM.
37301  *
37302  * To minimize creation of DOM elements, `ngRepeat` uses a function
37303  * to "keep track" of all items in the collection and their corresponding DOM elements.
37304  * For example, if an item is added to the collection, ngRepeat will know that all other items
37305  * already have DOM elements, and will not re-render them.
37306  *
37307  * The default tracking function (which tracks items by their identity) does not allow
37308  * duplicate items in arrays. This is because when there are duplicates, it is not possible
37309  * to maintain a one-to-one mapping between collection items and DOM elements.
37310  *
37311  * If you do need to repeat duplicate items, you can substitute the default tracking behavior
37312  * with your own using the `track by` expression.
37313  *
37314  * For example, you may track items by the index of each item in the collection, using the
37315  * special scope property `$index`:
37316  * ```html
37317  *    <div ng-repeat="n in [42, 42, 43, 43] track by $index">
37318  *      {{n}}
37319  *    </div>
37320  * ```
37321  *
37322  * You may also use arbitrary expressions in `track by`, including references to custom functions
37323  * on the scope:
37324  * ```html
37325  *    <div ng-repeat="n in [42, 42, 43, 43] track by myTrackingFunction(n)">
37326  *      {{n}}
37327  *    </div>
37328  * ```
37329  *
37330  * <div class="alert alert-success">
37331  * If you are working with objects that have an identifier property, you should track
37332  * by the identifier instead of the whole object. Should you reload your data later, `ngRepeat`
37333  * will not have to rebuild the DOM elements for items it has already rendered, even if the
37334  * JavaScript objects in the collection have been substituted for new ones. For large collections,
37335  * this significantly improves rendering performance. If you don't have a unique identifier,
37336  * `track by $index` can also provide a performance boost.
37337  * </div>
37338  * ```html
37339  *    <div ng-repeat="model in collection track by model.id">
37340  *      {{model.name}}
37341  *    </div>
37342  * ```
37343  *
37344  * When no `track by` expression is provided, it is equivalent to tracking by the built-in
37345  * `$id` function, which tracks items by their identity:
37346  * ```html
37347  *    <div ng-repeat="obj in collection track by $id(obj)">
37348  *      {{obj.prop}}
37349  *    </div>
37350  * ```
37351  *
37352  * <div class="alert alert-warning">
37353  * **Note:** `track by` must always be the last expression:
37354  * </div>
37355  * ```
37356  * <div ng-repeat="model in collection | orderBy: 'id' as filtered_result track by model.id">
37357  *     {{model.name}}
37358  * </div>
37359  * ```
37360  *
37361  * # Special repeat start and end points
37362  * To repeat a series of elements instead of just one parent element, ngRepeat (as well as other ng directives) supports extending
37363  * the range of the repeater by defining explicit start and end points by using **ng-repeat-start** and **ng-repeat-end** respectively.
37364  * 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)
37365  * up to and including the ending HTML tag where **ng-repeat-end** is placed.
37366  *
37367  * The example below makes use of this feature:
37368  * ```html
37369  *   <header ng-repeat-start="item in items">
37370  *     Header {{ item }}
37371  *   </header>
37372  *   <div class="body">
37373  *     Body {{ item }}
37374  *   </div>
37375  *   <footer ng-repeat-end>
37376  *     Footer {{ item }}
37377  *   </footer>
37378  * ```
37379  *
37380  * And with an input of {@type ['A','B']} for the items variable in the example above, the output will evaluate to:
37381  * ```html
37382  *   <header>
37383  *     Header A
37384  *   </header>
37385  *   <div class="body">
37386  *     Body A
37387  *   </div>
37388  *   <footer>
37389  *     Footer A
37390  *   </footer>
37391  *   <header>
37392  *     Header B
37393  *   </header>
37394  *   <div class="body">
37395  *     Body B
37396  *   </div>
37397  *   <footer>
37398  *     Footer B
37399  *   </footer>
37400  * ```
37401  *
37402  * The custom start and end points for ngRepeat also support all other HTML directive syntax flavors provided in AngularJS (such
37403  * as **data-ng-repeat-start**, **x-ng-repeat-start** and **ng:repeat-start**).
37404  *
37405  * @animations
37406  * **.enter** - when a new item is added to the list or when an item is revealed after a filter
37407  *
37408  * **.leave** - when an item is removed from the list or when an item is filtered out
37409  *
37410  * **.move** - when an adjacent item is filtered out causing a reorder or when the item contents are reordered
37411  *
37412  * See the example below for defining CSS animations with ngRepeat.
37413  *
37414  * @element ANY
37415  * @scope
37416  * @priority 1000
37417  * @param {repeat_expression} ngRepeat The expression indicating how to enumerate a collection. These
37418  *   formats are currently supported:
37419  *
37420  *   * `variable in expression` – where variable is the user defined loop variable and `expression`
37421  *     is a scope expression giving the collection to enumerate.
37422  *
37423  *     For example: `album in artist.albums`.
37424  *
37425  *   * `(key, value) in expression` – where `key` and `value` can be any user defined identifiers,
37426  *     and `expression` is the scope expression giving the collection to enumerate.
37427  *
37428  *     For example: `(name, age) in {'adam':10, 'amalie':12}`.
37429  *
37430  *   * `variable in expression track by tracking_expression` – You can also provide an optional tracking expression
37431  *     which can be used to associate the objects in the collection with the DOM elements. If no tracking expression
37432  *     is specified, ng-repeat associates elements by identity. It is an error to have
37433  *     more than one tracking expression value resolve to the same key. (This would mean that two distinct objects are
37434  *     mapped to the same DOM element, which is not possible.)
37435  *
37436  *     Note that the tracking expression must come last, after any filters, and the alias expression.
37437  *
37438  *     For example: `item in items` is equivalent to `item in items track by $id(item)`. This implies that the DOM elements
37439  *     will be associated by item identity in the array.
37440  *
37441  *     For example: `item in items track by $id(item)`. A built in `$id()` function can be used to assign a unique
37442  *     `$$hashKey` property to each item in the array. This property is then used as a key to associated DOM elements
37443  *     with the corresponding item in the array by identity. Moving the same object in array would move the DOM
37444  *     element in the same way in the DOM.
37445  *
37446  *     For example: `item in items track by item.id` is a typical pattern when the items come from the database. In this
37447  *     case the object identity does not matter. Two objects are considered equivalent as long as their `id`
37448  *     property is same.
37449  *
37450  *     For example: `item in items | filter:searchText track by item.id` is a pattern that might be used to apply a filter
37451  *     to items in conjunction with a tracking expression.
37452  *
37453  *   * `variable in expression as alias_expression` – You can also provide an optional alias expression which will then store the
37454  *     intermediate results of the repeater after the filters have been applied. Typically this is used to render a special message
37455  *     when a filter is active on the repeater, but the filtered result set is empty.
37456  *
37457  *     For example: `item in items | filter:x as results` will store the fragment of the repeated items as `results`, but only after
37458  *     the items have been processed through the filter.
37459  *
37460  *     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
37461  *     (and not as operator, inside an expression).
37462  *
37463  *     For example: `item in items | filter : x | orderBy : order | limitTo : limit as results` .
37464  *
37465  * @example
37466  * This example uses `ngRepeat` to display a list of people. A filter is used to restrict the displayed
37467  * results by name. New (entering) and removed (leaving) items are animated.
37468   <example module="ngRepeat" name="ngRepeat" deps="angular-animate.js" animations="true">
37469     <file name="index.html">
37470       <div ng-controller="repeatController">
37471         I have {{friends.length}} friends. They are:
37472         <input type="search" ng-model="q" placeholder="filter friends..." aria-label="filter friends" />
37473         <ul class="example-animate-container">
37474           <li class="animate-repeat" ng-repeat="friend in friends | filter:q as results">
37475             [{{$index + 1}}] {{friend.name}} who is {{friend.age}} years old.
37476           </li>
37477           <li class="animate-repeat" ng-if="results.length == 0">
37478             <strong>No results found...</strong>
37479           </li>
37480         </ul>
37481       </div>
37482     </file>
37483     <file name="script.js">
37484       angular.module('ngRepeat', ['ngAnimate']).controller('repeatController', function($scope) {
37485         $scope.friends = [
37486           {name:'John', age:25, gender:'boy'},
37487           {name:'Jessie', age:30, gender:'girl'},
37488           {name:'Johanna', age:28, gender:'girl'},
37489           {name:'Joy', age:15, gender:'girl'},
37490           {name:'Mary', age:28, gender:'girl'},
37491           {name:'Peter', age:95, gender:'boy'},
37492           {name:'Sebastian', age:50, gender:'boy'},
37493           {name:'Erika', age:27, gender:'girl'},
37494           {name:'Patrick', age:40, gender:'boy'},
37495           {name:'Samantha', age:60, gender:'girl'}
37496         ];
37497       });
37498     </file>
37499     <file name="animations.css">
37500       .example-animate-container {
37501         background:white;
37502         border:1px solid black;
37503         list-style:none;
37504         margin:0;
37505         padding:0 10px;
37506       }
37507
37508       .animate-repeat {
37509         line-height:30px;
37510         list-style:none;
37511         box-sizing:border-box;
37512       }
37513
37514       .animate-repeat.ng-move,
37515       .animate-repeat.ng-enter,
37516       .animate-repeat.ng-leave {
37517         transition:all linear 0.5s;
37518       }
37519
37520       .animate-repeat.ng-leave.ng-leave-active,
37521       .animate-repeat.ng-move,
37522       .animate-repeat.ng-enter {
37523         opacity:0;
37524         max-height:0;
37525       }
37526
37527       .animate-repeat.ng-leave,
37528       .animate-repeat.ng-move.ng-move-active,
37529       .animate-repeat.ng-enter.ng-enter-active {
37530         opacity:1;
37531         max-height:30px;
37532       }
37533     </file>
37534     <file name="protractor.js" type="protractor">
37535       var friends = element.all(by.repeater('friend in friends'));
37536
37537       it('should render initial data set', function() {
37538         expect(friends.count()).toBe(10);
37539         expect(friends.get(0).getText()).toEqual('[1] John who is 25 years old.');
37540         expect(friends.get(1).getText()).toEqual('[2] Jessie who is 30 years old.');
37541         expect(friends.last().getText()).toEqual('[10] Samantha who is 60 years old.');
37542         expect(element(by.binding('friends.length')).getText())
37543             .toMatch("I have 10 friends. They are:");
37544       });
37545
37546        it('should update repeater when filter predicate changes', function() {
37547          expect(friends.count()).toBe(10);
37548
37549          element(by.model('q')).sendKeys('ma');
37550
37551          expect(friends.count()).toBe(2);
37552          expect(friends.get(0).getText()).toEqual('[1] Mary who is 28 years old.');
37553          expect(friends.last().getText()).toEqual('[2] Samantha who is 60 years old.');
37554        });
37555       </file>
37556     </example>
37557  */
37558 var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
37559   var NG_REMOVED = '$$NG_REMOVED';
37560   var ngRepeatMinErr = minErr('ngRepeat');
37561
37562   var updateScope = function(scope, index, valueIdentifier, value, keyIdentifier, key, arrayLength) {
37563     // TODO(perf): generate setters to shave off ~40ms or 1-1.5%
37564     scope[valueIdentifier] = value;
37565     if (keyIdentifier) scope[keyIdentifier] = key;
37566     scope.$index = index;
37567     scope.$first = (index === 0);
37568     scope.$last = (index === (arrayLength - 1));
37569     scope.$middle = !(scope.$first || scope.$last);
37570     // jshint bitwise: false
37571     scope.$odd = !(scope.$even = (index&1) === 0);
37572     // jshint bitwise: true
37573   };
37574
37575   var getBlockStart = function(block) {
37576     return block.clone[0];
37577   };
37578
37579   var getBlockEnd = function(block) {
37580     return block.clone[block.clone.length - 1];
37581   };
37582
37583
37584   return {
37585     restrict: 'A',
37586     multiElement: true,
37587     transclude: 'element',
37588     priority: 1000,
37589     terminal: true,
37590     $$tlb: true,
37591     compile: function ngRepeatCompile($element, $attr) {
37592       var expression = $attr.ngRepeat;
37593       var ngRepeatEndComment = document.createComment(' end ngRepeat: ' + expression + ' ');
37594
37595       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*$/);
37596
37597       if (!match) {
37598         throw ngRepeatMinErr('iexp', "Expected expression in form of '_item_ in _collection_[ track by _id_]' but got '{0}'.",
37599             expression);
37600       }
37601
37602       var lhs = match[1];
37603       var rhs = match[2];
37604       var aliasAs = match[3];
37605       var trackByExp = match[4];
37606
37607       match = lhs.match(/^(?:(\s*[\$\w]+)|\(\s*([\$\w]+)\s*,\s*([\$\w]+)\s*\))$/);
37608
37609       if (!match) {
37610         throw ngRepeatMinErr('iidexp', "'_item_' in '_item_ in _collection_' should be an identifier or '(_key_, _value_)' expression, but got '{0}'.",
37611             lhs);
37612       }
37613       var valueIdentifier = match[3] || match[1];
37614       var keyIdentifier = match[2];
37615
37616       if (aliasAs && (!/^[$a-zA-Z_][$a-zA-Z0-9_]*$/.test(aliasAs) ||
37617           /^(null|undefined|this|\$index|\$first|\$middle|\$last|\$even|\$odd|\$parent|\$root|\$id)$/.test(aliasAs))) {
37618         throw ngRepeatMinErr('badident', "alias '{0}' is invalid --- must be a valid JS identifier which is not a reserved name.",
37619           aliasAs);
37620       }
37621
37622       var trackByExpGetter, trackByIdExpFn, trackByIdArrayFn, trackByIdObjFn;
37623       var hashFnLocals = {$id: hashKey};
37624
37625       if (trackByExp) {
37626         trackByExpGetter = $parse(trackByExp);
37627       } else {
37628         trackByIdArrayFn = function(key, value) {
37629           return hashKey(value);
37630         };
37631         trackByIdObjFn = function(key) {
37632           return key;
37633         };
37634       }
37635
37636       return function ngRepeatLink($scope, $element, $attr, ctrl, $transclude) {
37637
37638         if (trackByExpGetter) {
37639           trackByIdExpFn = function(key, value, index) {
37640             // assign key, value, and $index to the locals so that they can be used in hash functions
37641             if (keyIdentifier) hashFnLocals[keyIdentifier] = key;
37642             hashFnLocals[valueIdentifier] = value;
37643             hashFnLocals.$index = index;
37644             return trackByExpGetter($scope, hashFnLocals);
37645           };
37646         }
37647
37648         // Store a list of elements from previous run. This is a hash where key is the item from the
37649         // iterator, and the value is objects with following properties.
37650         //   - scope: bound scope
37651         //   - element: previous element.
37652         //   - index: position
37653         //
37654         // We are using no-proto object so that we don't need to guard against inherited props via
37655         // hasOwnProperty.
37656         var lastBlockMap = createMap();
37657
37658         //watch props
37659         $scope.$watchCollection(rhs, function ngRepeatAction(collection) {
37660           var index, length,
37661               previousNode = $element[0],     // node that cloned nodes should be inserted after
37662                                               // initialized to the comment node anchor
37663               nextNode,
37664               // Same as lastBlockMap but it has the current state. It will become the
37665               // lastBlockMap on the next iteration.
37666               nextBlockMap = createMap(),
37667               collectionLength,
37668               key, value, // key/value of iteration
37669               trackById,
37670               trackByIdFn,
37671               collectionKeys,
37672               block,       // last object information {scope, element, id}
37673               nextBlockOrder,
37674               elementsToRemove;
37675
37676           if (aliasAs) {
37677             $scope[aliasAs] = collection;
37678           }
37679
37680           if (isArrayLike(collection)) {
37681             collectionKeys = collection;
37682             trackByIdFn = trackByIdExpFn || trackByIdArrayFn;
37683           } else {
37684             trackByIdFn = trackByIdExpFn || trackByIdObjFn;
37685             // if object, extract keys, in enumeration order, unsorted
37686             collectionKeys = [];
37687             for (var itemKey in collection) {
37688               if (hasOwnProperty.call(collection, itemKey) && itemKey.charAt(0) !== '$') {
37689                 collectionKeys.push(itemKey);
37690               }
37691             }
37692           }
37693
37694           collectionLength = collectionKeys.length;
37695           nextBlockOrder = new Array(collectionLength);
37696
37697           // locate existing items
37698           for (index = 0; index < collectionLength; index++) {
37699             key = (collection === collectionKeys) ? index : collectionKeys[index];
37700             value = collection[key];
37701             trackById = trackByIdFn(key, value, index);
37702             if (lastBlockMap[trackById]) {
37703               // found previously seen block
37704               block = lastBlockMap[trackById];
37705               delete lastBlockMap[trackById];
37706               nextBlockMap[trackById] = block;
37707               nextBlockOrder[index] = block;
37708             } else if (nextBlockMap[trackById]) {
37709               // if collision detected. restore lastBlockMap and throw an error
37710               forEach(nextBlockOrder, function(block) {
37711                 if (block && block.scope) lastBlockMap[block.id] = block;
37712               });
37713               throw ngRepeatMinErr('dupes',
37714                   "Duplicates in a repeater are not allowed. Use 'track by' expression to specify unique keys. Repeater: {0}, Duplicate key: {1}, Duplicate value: {2}",
37715                   expression, trackById, value);
37716             } else {
37717               // new never before seen block
37718               nextBlockOrder[index] = {id: trackById, scope: undefined, clone: undefined};
37719               nextBlockMap[trackById] = true;
37720             }
37721           }
37722
37723           // remove leftover items
37724           for (var blockKey in lastBlockMap) {
37725             block = lastBlockMap[blockKey];
37726             elementsToRemove = getBlockNodes(block.clone);
37727             $animate.leave(elementsToRemove);
37728             if (elementsToRemove[0].parentNode) {
37729               // if the element was not removed yet because of pending animation, mark it as deleted
37730               // so that we can ignore it later
37731               for (index = 0, length = elementsToRemove.length; index < length; index++) {
37732                 elementsToRemove[index][NG_REMOVED] = true;
37733               }
37734             }
37735             block.scope.$destroy();
37736           }
37737
37738           // we are not using forEach for perf reasons (trying to avoid #call)
37739           for (index = 0; index < collectionLength; index++) {
37740             key = (collection === collectionKeys) ? index : collectionKeys[index];
37741             value = collection[key];
37742             block = nextBlockOrder[index];
37743
37744             if (block.scope) {
37745               // if we have already seen this object, then we need to reuse the
37746               // associated scope/element
37747
37748               nextNode = previousNode;
37749
37750               // skip nodes that are already pending removal via leave animation
37751               do {
37752                 nextNode = nextNode.nextSibling;
37753               } while (nextNode && nextNode[NG_REMOVED]);
37754
37755               if (getBlockStart(block) != nextNode) {
37756                 // existing item which got moved
37757                 $animate.move(getBlockNodes(block.clone), null, jqLite(previousNode));
37758               }
37759               previousNode = getBlockEnd(block);
37760               updateScope(block.scope, index, valueIdentifier, value, keyIdentifier, key, collectionLength);
37761             } else {
37762               // new item which we don't know about
37763               $transclude(function ngRepeatTransclude(clone, scope) {
37764                 block.scope = scope;
37765                 // http://jsperf.com/clone-vs-createcomment
37766                 var endNode = ngRepeatEndComment.cloneNode(false);
37767                 clone[clone.length++] = endNode;
37768
37769                 // TODO(perf): support naked previousNode in `enter` to avoid creation of jqLite wrapper?
37770                 $animate.enter(clone, null, jqLite(previousNode));
37771                 previousNode = endNode;
37772                 // Note: We only need the first/last node of the cloned nodes.
37773                 // However, we need to keep the reference to the jqlite wrapper as it might be changed later
37774                 // by a directive with templateUrl when its template arrives.
37775                 block.clone = clone;
37776                 nextBlockMap[block.id] = block;
37777                 updateScope(block.scope, index, valueIdentifier, value, keyIdentifier, key, collectionLength);
37778               });
37779             }
37780           }
37781           lastBlockMap = nextBlockMap;
37782         });
37783       };
37784     }
37785   };
37786 }];
37787
37788 var NG_HIDE_CLASS = 'ng-hide';
37789 var NG_HIDE_IN_PROGRESS_CLASS = 'ng-hide-animate';
37790 /**
37791  * @ngdoc directive
37792  * @name ngShow
37793  * @multiElement
37794  *
37795  * @description
37796  * The `ngShow` directive shows or hides the given HTML element based on the expression
37797  * provided to the `ngShow` attribute. The element is shown or hidden by removing or adding
37798  * the `.ng-hide` CSS class onto the element. The `.ng-hide` CSS class is predefined
37799  * in AngularJS and sets the display style to none (using an !important flag).
37800  * For CSP mode please add `angular-csp.css` to your html file (see {@link ng.directive:ngCsp ngCsp}).
37801  *
37802  * ```html
37803  * <!-- when $scope.myValue is truthy (element is visible) -->
37804  * <div ng-show="myValue"></div>
37805  *
37806  * <!-- when $scope.myValue is falsy (element is hidden) -->
37807  * <div ng-show="myValue" class="ng-hide"></div>
37808  * ```
37809  *
37810  * When the `ngShow` expression evaluates to a falsy value then the `.ng-hide` CSS class is added to the class
37811  * attribute on the element causing it to become hidden. When truthy, the `.ng-hide` CSS class is removed
37812  * from the element causing the element not to appear hidden.
37813  *
37814  * ## Why is !important used?
37815  *
37816  * You may be wondering why !important is used for the `.ng-hide` CSS class. This is because the `.ng-hide` selector
37817  * can be easily overridden by heavier selectors. For example, something as simple
37818  * as changing the display style on a HTML list item would make hidden elements appear visible.
37819  * This also becomes a bigger issue when dealing with CSS frameworks.
37820  *
37821  * By using !important, the show and hide behavior will work as expected despite any clash between CSS selector
37822  * specificity (when !important isn't used with any conflicting styles). If a developer chooses to override the
37823  * styling to change how to hide an element then it is just a matter of using !important in their own CSS code.
37824  *
37825  * ### Overriding `.ng-hide`
37826  *
37827  * By default, the `.ng-hide` class will style the element with `display: none!important`. If you wish to change
37828  * the hide behavior with ngShow/ngHide then this can be achieved by restating the styles for the `.ng-hide`
37829  * class CSS. Note that the selector that needs to be used is actually `.ng-hide:not(.ng-hide-animate)` to cope
37830  * with extra animation classes that can be added.
37831  *
37832  * ```css
37833  * .ng-hide:not(.ng-hide-animate) {
37834  *   /&#42; this is just another form of hiding an element &#42;/
37835  *   display: block!important;
37836  *   position: absolute;
37837  *   top: -9999px;
37838  *   left: -9999px;
37839  * }
37840  * ```
37841  *
37842  * By default you don't need to override in CSS anything and the animations will work around the display style.
37843  *
37844  * ## A note about animations with `ngShow`
37845  *
37846  * Animations in ngShow/ngHide work with the show and hide events that are triggered when the directive expression
37847  * is true and false. This system works like the animation system present with ngClass except that
37848  * you must also include the !important flag to override the display property
37849  * so that you can perform an animation when the element is hidden during the time of the animation.
37850  *
37851  * ```css
37852  * //
37853  * //a working example can be found at the bottom of this page
37854  * //
37855  * .my-element.ng-hide-add, .my-element.ng-hide-remove {
37856  *   /&#42; this is required as of 1.3x to properly
37857  *      apply all styling in a show/hide animation &#42;/
37858  *   transition: 0s linear all;
37859  * }
37860  *
37861  * .my-element.ng-hide-add-active,
37862  * .my-element.ng-hide-remove-active {
37863  *   /&#42; the transition is defined in the active class &#42;/
37864  *   transition: 1s linear all;
37865  * }
37866  *
37867  * .my-element.ng-hide-add { ... }
37868  * .my-element.ng-hide-add.ng-hide-add-active { ... }
37869  * .my-element.ng-hide-remove { ... }
37870  * .my-element.ng-hide-remove.ng-hide-remove-active { ... }
37871  * ```
37872  *
37873  * Keep in mind that, as of AngularJS version 1.3.0-beta.11, there is no need to change the display
37874  * property to block during animation states--ngAnimate will handle the style toggling automatically for you.
37875  *
37876  * @animations
37877  * addClass: `.ng-hide` - happens after the `ngShow` expression evaluates to a truthy value and the just before contents are set to visible
37878  * removeClass: `.ng-hide` - happens after the `ngShow` expression evaluates to a non truthy value and just before the contents are set to hidden
37879  *
37880  * @element ANY
37881  * @param {expression} ngShow If the {@link guide/expression expression} is truthy
37882  *     then the element is shown or hidden respectively.
37883  *
37884  * @example
37885   <example module="ngAnimate" deps="angular-animate.js" animations="true">
37886     <file name="index.html">
37887       Click me: <input type="checkbox" ng-model="checked" aria-label="Toggle ngHide"><br/>
37888       <div>
37889         Show:
37890         <div class="check-element animate-show" ng-show="checked">
37891           <span class="glyphicon glyphicon-thumbs-up"></span> I show up when your checkbox is checked.
37892         </div>
37893       </div>
37894       <div>
37895         Hide:
37896         <div class="check-element animate-show" ng-hide="checked">
37897           <span class="glyphicon glyphicon-thumbs-down"></span> I hide when your checkbox is checked.
37898         </div>
37899       </div>
37900     </file>
37901     <file name="glyphicons.css">
37902       @import url(../../components/bootstrap-3.1.1/css/bootstrap.css);
37903     </file>
37904     <file name="animations.css">
37905       .animate-show {
37906         line-height: 20px;
37907         opacity: 1;
37908         padding: 10px;
37909         border: 1px solid black;
37910         background: white;
37911       }
37912
37913       .animate-show.ng-hide-add, .animate-show.ng-hide-remove {
37914         transition: all linear 0.5s;
37915       }
37916
37917       .animate-show.ng-hide {
37918         line-height: 0;
37919         opacity: 0;
37920         padding: 0 10px;
37921       }
37922
37923       .check-element {
37924         padding: 10px;
37925         border: 1px solid black;
37926         background: white;
37927       }
37928     </file>
37929     <file name="protractor.js" type="protractor">
37930       var thumbsUp = element(by.css('span.glyphicon-thumbs-up'));
37931       var thumbsDown = element(by.css('span.glyphicon-thumbs-down'));
37932
37933       it('should check ng-show / ng-hide', function() {
37934         expect(thumbsUp.isDisplayed()).toBeFalsy();
37935         expect(thumbsDown.isDisplayed()).toBeTruthy();
37936
37937         element(by.model('checked')).click();
37938
37939         expect(thumbsUp.isDisplayed()).toBeTruthy();
37940         expect(thumbsDown.isDisplayed()).toBeFalsy();
37941       });
37942     </file>
37943   </example>
37944  */
37945 var ngShowDirective = ['$animate', function($animate) {
37946   return {
37947     restrict: 'A',
37948     multiElement: true,
37949     link: function(scope, element, attr) {
37950       scope.$watch(attr.ngShow, function ngShowWatchAction(value) {
37951         // we're adding a temporary, animation-specific class for ng-hide since this way
37952         // we can control when the element is actually displayed on screen without having
37953         // to have a global/greedy CSS selector that breaks when other animations are run.
37954         // Read: https://github.com/angular/angular.js/issues/9103#issuecomment-58335845
37955         $animate[value ? 'removeClass' : 'addClass'](element, NG_HIDE_CLASS, {
37956           tempClasses: NG_HIDE_IN_PROGRESS_CLASS
37957         });
37958       });
37959     }
37960   };
37961 }];
37962
37963
37964 /**
37965  * @ngdoc directive
37966  * @name ngHide
37967  * @multiElement
37968  *
37969  * @description
37970  * The `ngHide` directive shows or hides the given HTML element based on the expression
37971  * provided to the `ngHide` attribute. The element is shown or hidden by removing or adding
37972  * the `ng-hide` CSS class onto the element. The `.ng-hide` CSS class is predefined
37973  * in AngularJS and sets the display style to none (using an !important flag).
37974  * For CSP mode please add `angular-csp.css` to your html file (see {@link ng.directive:ngCsp ngCsp}).
37975  *
37976  * ```html
37977  * <!-- when $scope.myValue is truthy (element is hidden) -->
37978  * <div ng-hide="myValue" class="ng-hide"></div>
37979  *
37980  * <!-- when $scope.myValue is falsy (element is visible) -->
37981  * <div ng-hide="myValue"></div>
37982  * ```
37983  *
37984  * When the `ngHide` expression evaluates to a truthy value then the `.ng-hide` CSS class is added to the class
37985  * attribute on the element causing it to become hidden. When falsy, the `.ng-hide` CSS class is removed
37986  * from the element causing the element not to appear hidden.
37987  *
37988  * ## Why is !important used?
37989  *
37990  * You may be wondering why !important is used for the `.ng-hide` CSS class. This is because the `.ng-hide` selector
37991  * can be easily overridden by heavier selectors. For example, something as simple
37992  * as changing the display style on a HTML list item would make hidden elements appear visible.
37993  * This also becomes a bigger issue when dealing with CSS frameworks.
37994  *
37995  * By using !important, the show and hide behavior will work as expected despite any clash between CSS selector
37996  * specificity (when !important isn't used with any conflicting styles). If a developer chooses to override the
37997  * styling to change how to hide an element then it is just a matter of using !important in their own CSS code.
37998  *
37999  * ### Overriding `.ng-hide`
38000  *
38001  * By default, the `.ng-hide` class will style the element with `display: none!important`. If you wish to change
38002  * the hide behavior with ngShow/ngHide then this can be achieved by restating the styles for the `.ng-hide`
38003  * class in CSS:
38004  *
38005  * ```css
38006  * .ng-hide {
38007  *   /&#42; this is just another form of hiding an element &#42;/
38008  *   display: block!important;
38009  *   position: absolute;
38010  *   top: -9999px;
38011  *   left: -9999px;
38012  * }
38013  * ```
38014  *
38015  * By default you don't need to override in CSS anything and the animations will work around the display style.
38016  *
38017  * ## A note about animations with `ngHide`
38018  *
38019  * Animations in ngShow/ngHide work with the show and hide events that are triggered when the directive expression
38020  * is true and false. This system works like the animation system present with ngClass, except that the `.ng-hide`
38021  * CSS class is added and removed for you instead of your own CSS class.
38022  *
38023  * ```css
38024  * //
38025  * //a working example can be found at the bottom of this page
38026  * //
38027  * .my-element.ng-hide-add, .my-element.ng-hide-remove {
38028  *   transition: 0.5s linear all;
38029  * }
38030  *
38031  * .my-element.ng-hide-add { ... }
38032  * .my-element.ng-hide-add.ng-hide-add-active { ... }
38033  * .my-element.ng-hide-remove { ... }
38034  * .my-element.ng-hide-remove.ng-hide-remove-active { ... }
38035  * ```
38036  *
38037  * Keep in mind that, as of AngularJS version 1.3.0-beta.11, there is no need to change the display
38038  * property to block during animation states--ngAnimate will handle the style toggling automatically for you.
38039  *
38040  * @animations
38041  * removeClass: `.ng-hide` - happens after the `ngHide` expression evaluates to a truthy value and just before the contents are set to hidden
38042  * addClass: `.ng-hide` - happens after the `ngHide` expression evaluates to a non truthy value and just before the contents are set to visible
38043  *
38044  * @element ANY
38045  * @param {expression} ngHide If the {@link guide/expression expression} is truthy then
38046  *     the element is shown or hidden respectively.
38047  *
38048  * @example
38049   <example module="ngAnimate" deps="angular-animate.js" animations="true">
38050     <file name="index.html">
38051       Click me: <input type="checkbox" ng-model="checked" aria-label="Toggle ngShow"><br/>
38052       <div>
38053         Show:
38054         <div class="check-element animate-hide" ng-show="checked">
38055           <span class="glyphicon glyphicon-thumbs-up"></span> I show up when your checkbox is checked.
38056         </div>
38057       </div>
38058       <div>
38059         Hide:
38060         <div class="check-element animate-hide" ng-hide="checked">
38061           <span class="glyphicon glyphicon-thumbs-down"></span> I hide when your checkbox is checked.
38062         </div>
38063       </div>
38064     </file>
38065     <file name="glyphicons.css">
38066       @import url(../../components/bootstrap-3.1.1/css/bootstrap.css);
38067     </file>
38068     <file name="animations.css">
38069       .animate-hide {
38070         transition: all linear 0.5s;
38071         line-height: 20px;
38072         opacity: 1;
38073         padding: 10px;
38074         border: 1px solid black;
38075         background: white;
38076       }
38077
38078       .animate-hide.ng-hide {
38079         line-height: 0;
38080         opacity: 0;
38081         padding: 0 10px;
38082       }
38083
38084       .check-element {
38085         padding: 10px;
38086         border: 1px solid black;
38087         background: white;
38088       }
38089     </file>
38090     <file name="protractor.js" type="protractor">
38091       var thumbsUp = element(by.css('span.glyphicon-thumbs-up'));
38092       var thumbsDown = element(by.css('span.glyphicon-thumbs-down'));
38093
38094       it('should check ng-show / ng-hide', function() {
38095         expect(thumbsUp.isDisplayed()).toBeFalsy();
38096         expect(thumbsDown.isDisplayed()).toBeTruthy();
38097
38098         element(by.model('checked')).click();
38099
38100         expect(thumbsUp.isDisplayed()).toBeTruthy();
38101         expect(thumbsDown.isDisplayed()).toBeFalsy();
38102       });
38103     </file>
38104   </example>
38105  */
38106 var ngHideDirective = ['$animate', function($animate) {
38107   return {
38108     restrict: 'A',
38109     multiElement: true,
38110     link: function(scope, element, attr) {
38111       scope.$watch(attr.ngHide, function ngHideWatchAction(value) {
38112         // The comment inside of the ngShowDirective explains why we add and
38113         // remove a temporary class for the show/hide animation
38114         $animate[value ? 'addClass' : 'removeClass'](element,NG_HIDE_CLASS, {
38115           tempClasses: NG_HIDE_IN_PROGRESS_CLASS
38116         });
38117       });
38118     }
38119   };
38120 }];
38121
38122 /**
38123  * @ngdoc directive
38124  * @name ngStyle
38125  * @restrict AC
38126  *
38127  * @description
38128  * The `ngStyle` directive allows you to set CSS style on an HTML element conditionally.
38129  *
38130  * @element ANY
38131  * @param {expression} ngStyle
38132  *
38133  * {@link guide/expression Expression} which evals to an
38134  * object whose keys are CSS style names and values are corresponding values for those CSS
38135  * keys.
38136  *
38137  * Since some CSS style names are not valid keys for an object, they must be quoted.
38138  * See the 'background-color' style in the example below.
38139  *
38140  * @example
38141    <example>
38142      <file name="index.html">
38143         <input type="button" value="set color" ng-click="myStyle={color:'red'}">
38144         <input type="button" value="set background" ng-click="myStyle={'background-color':'blue'}">
38145         <input type="button" value="clear" ng-click="myStyle={}">
38146         <br/>
38147         <span ng-style="myStyle">Sample Text</span>
38148         <pre>myStyle={{myStyle}}</pre>
38149      </file>
38150      <file name="style.css">
38151        span {
38152          color: black;
38153        }
38154      </file>
38155      <file name="protractor.js" type="protractor">
38156        var colorSpan = element(by.css('span'));
38157
38158        it('should check ng-style', function() {
38159          expect(colorSpan.getCssValue('color')).toBe('rgba(0, 0, 0, 1)');
38160          element(by.css('input[value=\'set color\']')).click();
38161          expect(colorSpan.getCssValue('color')).toBe('rgba(255, 0, 0, 1)');
38162          element(by.css('input[value=clear]')).click();
38163          expect(colorSpan.getCssValue('color')).toBe('rgba(0, 0, 0, 1)');
38164        });
38165      </file>
38166    </example>
38167  */
38168 var ngStyleDirective = ngDirective(function(scope, element, attr) {
38169   scope.$watch(attr.ngStyle, function ngStyleWatchAction(newStyles, oldStyles) {
38170     if (oldStyles && (newStyles !== oldStyles)) {
38171       forEach(oldStyles, function(val, style) { element.css(style, '');});
38172     }
38173     if (newStyles) element.css(newStyles);
38174   }, true);
38175 });
38176
38177 /**
38178  * @ngdoc directive
38179  * @name ngSwitch
38180  * @restrict EA
38181  *
38182  * @description
38183  * The `ngSwitch` directive is used to conditionally swap DOM structure on your template based on a scope expression.
38184  * Elements within `ngSwitch` but without `ngSwitchWhen` or `ngSwitchDefault` directives will be preserved at the location
38185  * as specified in the template.
38186  *
38187  * The directive itself works similar to ngInclude, however, instead of downloading template code (or loading it
38188  * from the template cache), `ngSwitch` simply chooses one of the nested elements and makes it visible based on which element
38189  * matches the value obtained from the evaluated expression. In other words, you define a container element
38190  * (where you place the directive), place an expression on the **`on="..."` attribute**
38191  * (or the **`ng-switch="..."` attribute**), define any inner elements inside of the directive and place
38192  * a when attribute per element. The when attribute is used to inform ngSwitch which element to display when the on
38193  * expression is evaluated. If a matching expression is not found via a when attribute then an element with the default
38194  * attribute is displayed.
38195  *
38196  * <div class="alert alert-info">
38197  * Be aware that the attribute values to match against cannot be expressions. They are interpreted
38198  * as literal string values to match against.
38199  * For example, **`ng-switch-when="someVal"`** will match against the string `"someVal"` not against the
38200  * value of the expression `$scope.someVal`.
38201  * </div>
38202
38203  * @animations
38204  * enter - happens after the ngSwitch contents change and the matched child element is placed inside the container
38205  * leave - happens just after the ngSwitch contents change and just before the former contents are removed from the DOM
38206  *
38207  * @usage
38208  *
38209  * ```
38210  * <ANY ng-switch="expression">
38211  *   <ANY ng-switch-when="matchValue1">...</ANY>
38212  *   <ANY ng-switch-when="matchValue2">...</ANY>
38213  *   <ANY ng-switch-default>...</ANY>
38214  * </ANY>
38215  * ```
38216  *
38217  *
38218  * @scope
38219  * @priority 1200
38220  * @param {*} ngSwitch|on expression to match against <code>ng-switch-when</code>.
38221  * On child elements add:
38222  *
38223  * * `ngSwitchWhen`: the case statement to match against. If match then this
38224  *   case will be displayed. If the same match appears multiple times, all the
38225  *   elements will be displayed.
38226  * * `ngSwitchDefault`: the default case when no other case match. If there
38227  *   are multiple default cases, all of them will be displayed when no other
38228  *   case match.
38229  *
38230  *
38231  * @example
38232   <example module="switchExample" deps="angular-animate.js" animations="true">
38233     <file name="index.html">
38234       <div ng-controller="ExampleController">
38235         <select ng-model="selection" ng-options="item for item in items">
38236         </select>
38237         <code>selection={{selection}}</code>
38238         <hr/>
38239         <div class="animate-switch-container"
38240           ng-switch on="selection">
38241             <div class="animate-switch" ng-switch-when="settings">Settings Div</div>
38242             <div class="animate-switch" ng-switch-when="home">Home Span</div>
38243             <div class="animate-switch" ng-switch-default>default</div>
38244         </div>
38245       </div>
38246     </file>
38247     <file name="script.js">
38248       angular.module('switchExample', ['ngAnimate'])
38249         .controller('ExampleController', ['$scope', function($scope) {
38250           $scope.items = ['settings', 'home', 'other'];
38251           $scope.selection = $scope.items[0];
38252         }]);
38253     </file>
38254     <file name="animations.css">
38255       .animate-switch-container {
38256         position:relative;
38257         background:white;
38258         border:1px solid black;
38259         height:40px;
38260         overflow:hidden;
38261       }
38262
38263       .animate-switch {
38264         padding:10px;
38265       }
38266
38267       .animate-switch.ng-animate {
38268         transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
38269
38270         position:absolute;
38271         top:0;
38272         left:0;
38273         right:0;
38274         bottom:0;
38275       }
38276
38277       .animate-switch.ng-leave.ng-leave-active,
38278       .animate-switch.ng-enter {
38279         top:-50px;
38280       }
38281       .animate-switch.ng-leave,
38282       .animate-switch.ng-enter.ng-enter-active {
38283         top:0;
38284       }
38285     </file>
38286     <file name="protractor.js" type="protractor">
38287       var switchElem = element(by.css('[ng-switch]'));
38288       var select = element(by.model('selection'));
38289
38290       it('should start in settings', function() {
38291         expect(switchElem.getText()).toMatch(/Settings Div/);
38292       });
38293       it('should change to home', function() {
38294         select.all(by.css('option')).get(1).click();
38295         expect(switchElem.getText()).toMatch(/Home Span/);
38296       });
38297       it('should select default', function() {
38298         select.all(by.css('option')).get(2).click();
38299         expect(switchElem.getText()).toMatch(/default/);
38300       });
38301     </file>
38302   </example>
38303  */
38304 var ngSwitchDirective = ['$animate', function($animate) {
38305   return {
38306     require: 'ngSwitch',
38307
38308     // asks for $scope to fool the BC controller module
38309     controller: ['$scope', function ngSwitchController() {
38310      this.cases = {};
38311     }],
38312     link: function(scope, element, attr, ngSwitchController) {
38313       var watchExpr = attr.ngSwitch || attr.on,
38314           selectedTranscludes = [],
38315           selectedElements = [],
38316           previousLeaveAnimations = [],
38317           selectedScopes = [];
38318
38319       var spliceFactory = function(array, index) {
38320           return function() { array.splice(index, 1); };
38321       };
38322
38323       scope.$watch(watchExpr, function ngSwitchWatchAction(value) {
38324         var i, ii;
38325         for (i = 0, ii = previousLeaveAnimations.length; i < ii; ++i) {
38326           $animate.cancel(previousLeaveAnimations[i]);
38327         }
38328         previousLeaveAnimations.length = 0;
38329
38330         for (i = 0, ii = selectedScopes.length; i < ii; ++i) {
38331           var selected = getBlockNodes(selectedElements[i].clone);
38332           selectedScopes[i].$destroy();
38333           var promise = previousLeaveAnimations[i] = $animate.leave(selected);
38334           promise.then(spliceFactory(previousLeaveAnimations, i));
38335         }
38336
38337         selectedElements.length = 0;
38338         selectedScopes.length = 0;
38339
38340         if ((selectedTranscludes = ngSwitchController.cases['!' + value] || ngSwitchController.cases['?'])) {
38341           forEach(selectedTranscludes, function(selectedTransclude) {
38342             selectedTransclude.transclude(function(caseElement, selectedScope) {
38343               selectedScopes.push(selectedScope);
38344               var anchor = selectedTransclude.element;
38345               caseElement[caseElement.length++] = document.createComment(' end ngSwitchWhen: ');
38346               var block = { clone: caseElement };
38347
38348               selectedElements.push(block);
38349               $animate.enter(caseElement, anchor.parent(), anchor);
38350             });
38351           });
38352         }
38353       });
38354     }
38355   };
38356 }];
38357
38358 var ngSwitchWhenDirective = ngDirective({
38359   transclude: 'element',
38360   priority: 1200,
38361   require: '^ngSwitch',
38362   multiElement: true,
38363   link: function(scope, element, attrs, ctrl, $transclude) {
38364     ctrl.cases['!' + attrs.ngSwitchWhen] = (ctrl.cases['!' + attrs.ngSwitchWhen] || []);
38365     ctrl.cases['!' + attrs.ngSwitchWhen].push({ transclude: $transclude, element: element });
38366   }
38367 });
38368
38369 var ngSwitchDefaultDirective = ngDirective({
38370   transclude: 'element',
38371   priority: 1200,
38372   require: '^ngSwitch',
38373   multiElement: true,
38374   link: function(scope, element, attr, ctrl, $transclude) {
38375     ctrl.cases['?'] = (ctrl.cases['?'] || []);
38376     ctrl.cases['?'].push({ transclude: $transclude, element: element });
38377    }
38378 });
38379
38380 /**
38381  * @ngdoc directive
38382  * @name ngTransclude
38383  * @restrict EAC
38384  *
38385  * @description
38386  * Directive that marks the insertion point for the transcluded DOM of the nearest parent directive that uses transclusion.
38387  *
38388  * You can specify that you want to insert a named transclusion slot, instead of the default slot, by providing the slot name
38389  * as the value of the `ng-transclude` or `ng-transclude-slot` attribute.
38390  *
38391  * If the transcluded content is not empty (i.e. contains one or more DOM nodes, including whitespace text nodes), any existing
38392  * content of this element will be removed before the transcluded content is inserted.
38393  * If the transcluded content is empty, the existing content is left intact. This lets you provide fallback content in the case
38394  * that no transcluded content is provided.
38395  *
38396  * @element ANY
38397  *
38398  * @param {string} ngTransclude|ngTranscludeSlot the name of the slot to insert at this point. If this is not provided, is empty
38399  *                                               or its value is the same as the name of the attribute then the default slot is used.
38400  *
38401  * @example
38402  * ### Basic transclusion
38403  * This example demonstrates basic transclusion of content into a component directive.
38404  * <example name="simpleTranscludeExample" module="transcludeExample">
38405  *   <file name="index.html">
38406  *     <script>
38407  *       angular.module('transcludeExample', [])
38408  *        .directive('pane', function(){
38409  *           return {
38410  *             restrict: 'E',
38411  *             transclude: true,
38412  *             scope: { title:'@' },
38413  *             template: '<div style="border: 1px solid black;">' +
38414  *                         '<div style="background-color: gray">{{title}}</div>' +
38415  *                         '<ng-transclude></ng-transclude>' +
38416  *                       '</div>'
38417  *           };
38418  *       })
38419  *       .controller('ExampleController', ['$scope', function($scope) {
38420  *         $scope.title = 'Lorem Ipsum';
38421  *         $scope.text = 'Neque porro quisquam est qui dolorem ipsum quia dolor...';
38422  *       }]);
38423  *     </script>
38424  *     <div ng-controller="ExampleController">
38425  *       <input ng-model="title" aria-label="title"> <br/>
38426  *       <textarea ng-model="text" aria-label="text"></textarea> <br/>
38427  *       <pane title="{{title}}">{{text}}</pane>
38428  *     </div>
38429  *   </file>
38430  *   <file name="protractor.js" type="protractor">
38431  *      it('should have transcluded', function() {
38432  *        var titleElement = element(by.model('title'));
38433  *        titleElement.clear();
38434  *        titleElement.sendKeys('TITLE');
38435  *        var textElement = element(by.model('text'));
38436  *        textElement.clear();
38437  *        textElement.sendKeys('TEXT');
38438  *        expect(element(by.binding('title')).getText()).toEqual('TITLE');
38439  *        expect(element(by.binding('text')).getText()).toEqual('TEXT');
38440  *      });
38441  *   </file>
38442  * </example>
38443  *
38444  * @example
38445  * ### Transclude fallback content
38446  * This example shows how to use `NgTransclude` with fallback content, that
38447  * is displayed if no transcluded content is provided.
38448  *
38449  * <example module="transcludeFallbackContentExample">
38450  * <file name="index.html">
38451  * <script>
38452  * angular.module('transcludeFallbackContentExample', [])
38453  * .directive('myButton', function(){
38454  *             return {
38455  *               restrict: 'E',
38456  *               transclude: true,
38457  *               scope: true,
38458  *               template: '<button style="cursor: pointer;">' +
38459  *                           '<ng-transclude>' +
38460  *                             '<b style="color: red;">Button1</b>' +
38461  *                           '</ng-transclude>' +
38462  *                         '</button>'
38463  *             };
38464  *         });
38465  * </script>
38466  * <!-- fallback button content -->
38467  * <my-button id="fallback"></my-button>
38468  * <!-- modified button content -->
38469  * <my-button id="modified">
38470  *   <i style="color: green;">Button2</i>
38471  * </my-button>
38472  * </file>
38473  * <file name="protractor.js" type="protractor">
38474  * it('should have different transclude element content', function() {
38475  *          expect(element(by.id('fallback')).getText()).toBe('Button1');
38476  *          expect(element(by.id('modified')).getText()).toBe('Button2');
38477  *        });
38478  * </file>
38479  * </example>
38480  *
38481  * @example
38482  * ### Multi-slot transclusion
38483  * This example demonstrates using multi-slot transclusion in a component directive.
38484  * <example name="multiSlotTranscludeExample" module="multiSlotTranscludeExample">
38485  *   <file name="index.html">
38486  *    <style>
38487  *      .title, .footer {
38488  *        background-color: gray
38489  *      }
38490  *    </style>
38491  *    <div ng-controller="ExampleController">
38492  *      <input ng-model="title" aria-label="title"> <br/>
38493  *      <textarea ng-model="text" aria-label="text"></textarea> <br/>
38494  *      <pane>
38495  *        <pane-title><a ng-href="{{link}}">{{title}}</a></pane-title>
38496  *        <pane-body><p>{{text}}</p></pane-body>
38497  *      </pane>
38498  *    </div>
38499  *   </file>
38500  *   <file name="app.js">
38501  *    angular.module('multiSlotTranscludeExample', [])
38502  *     .directive('pane', function(){
38503  *        return {
38504  *          restrict: 'E',
38505  *          transclude: {
38506  *            'title': '?paneTitle',
38507  *            'body': 'paneBody',
38508  *            'footer': '?paneFooter'
38509  *          },
38510  *          template: '<div style="border: 1px solid black;">' +
38511  *                      '<div class="title" ng-transclude="title">Fallback Title</div>' +
38512  *                      '<div ng-transclude="body"></div>' +
38513  *                      '<div class="footer" ng-transclude="footer">Fallback Footer</div>' +
38514  *                    '</div>'
38515  *        };
38516  *    })
38517  *    .controller('ExampleController', ['$scope', function($scope) {
38518  *      $scope.title = 'Lorem Ipsum';
38519  *      $scope.link = "https://google.com";
38520  *      $scope.text = 'Neque porro quisquam est qui dolorem ipsum quia dolor...';
38521  *    }]);
38522  *   </file>
38523  *   <file name="protractor.js" type="protractor">
38524  *      it('should have transcluded the title and the body', function() {
38525  *        var titleElement = element(by.model('title'));
38526  *        titleElement.clear();
38527  *        titleElement.sendKeys('TITLE');
38528  *        var textElement = element(by.model('text'));
38529  *        textElement.clear();
38530  *        textElement.sendKeys('TEXT');
38531  *        expect(element(by.css('.title')).getText()).toEqual('TITLE');
38532  *        expect(element(by.binding('text')).getText()).toEqual('TEXT');
38533  *        expect(element(by.css('.footer')).getText()).toEqual('Fallback Footer');
38534  *      });
38535  *   </file>
38536  * </example>
38537  */
38538 var ngTranscludeMinErr = minErr('ngTransclude');
38539 var ngTranscludeDirective = ngDirective({
38540   restrict: 'EAC',
38541   link: function($scope, $element, $attrs, controller, $transclude) {
38542
38543     if ($attrs.ngTransclude === $attrs.$attr.ngTransclude) {
38544       // If the attribute is of the form: `ng-transclude="ng-transclude"`
38545       // then treat it like the default
38546       $attrs.ngTransclude = '';
38547     }
38548
38549     function ngTranscludeCloneAttachFn(clone) {
38550       if (clone.length) {
38551         $element.empty();
38552         $element.append(clone);
38553       }
38554     }
38555
38556     if (!$transclude) {
38557       throw ngTranscludeMinErr('orphan',
38558        'Illegal use of ngTransclude directive in the template! ' +
38559        'No parent directive that requires a transclusion found. ' +
38560        'Element: {0}',
38561        startingTag($element));
38562     }
38563
38564     // If there is no slot name defined or the slot name is not optional
38565     // then transclude the slot
38566     var slotName = $attrs.ngTransclude || $attrs.ngTranscludeSlot;
38567     $transclude(ngTranscludeCloneAttachFn, null, slotName);
38568   }
38569 });
38570
38571 /**
38572  * @ngdoc directive
38573  * @name script
38574  * @restrict E
38575  *
38576  * @description
38577  * Load the content of a `<script>` element into {@link ng.$templateCache `$templateCache`}, so that the
38578  * template can be used by {@link ng.directive:ngInclude `ngInclude`},
38579  * {@link ngRoute.directive:ngView `ngView`}, or {@link guide/directive directives}. The type of the
38580  * `<script>` element must be specified as `text/ng-template`, and a cache name for the template must be
38581  * assigned through the element's `id`, which can then be used as a directive's `templateUrl`.
38582  *
38583  * @param {string} type Must be set to `'text/ng-template'`.
38584  * @param {string} id Cache name of the template.
38585  *
38586  * @example
38587   <example>
38588     <file name="index.html">
38589       <script type="text/ng-template" id="/tpl.html">
38590         Content of the template.
38591       </script>
38592
38593       <a ng-click="currentTpl='/tpl.html'" id="tpl-link">Load inlined template</a>
38594       <div id="tpl-content" ng-include src="currentTpl"></div>
38595     </file>
38596     <file name="protractor.js" type="protractor">
38597       it('should load template defined inside script tag', function() {
38598         element(by.css('#tpl-link')).click();
38599         expect(element(by.css('#tpl-content')).getText()).toMatch(/Content of the template/);
38600       });
38601     </file>
38602   </example>
38603  */
38604 var scriptDirective = ['$templateCache', function($templateCache) {
38605   return {
38606     restrict: 'E',
38607     terminal: true,
38608     compile: function(element, attr) {
38609       if (attr.type == 'text/ng-template') {
38610         var templateUrl = attr.id,
38611             text = element[0].text;
38612
38613         $templateCache.put(templateUrl, text);
38614       }
38615     }
38616   };
38617 }];
38618
38619 var noopNgModelController = { $setViewValue: noop, $render: noop };
38620
38621 function chromeHack(optionElement) {
38622   // Workaround for https://code.google.com/p/chromium/issues/detail?id=381459
38623   // Adding an <option selected="selected"> element to a <select required="required"> should
38624   // automatically select the new element
38625   if (optionElement[0].hasAttribute('selected')) {
38626     optionElement[0].selected = true;
38627   }
38628 }
38629
38630 /**
38631  * @ngdoc type
38632  * @name  select.SelectController
38633  * @description
38634  * The controller for the `<select>` directive. This provides support for reading
38635  * and writing the selected value(s) of the control and also coordinates dynamically
38636  * added `<option>` elements, perhaps by an `ngRepeat` directive.
38637  */
38638 var SelectController =
38639         ['$element', '$scope', '$attrs', function($element, $scope, $attrs) {
38640
38641   var self = this,
38642       optionsMap = new HashMap();
38643
38644   // If the ngModel doesn't get provided then provide a dummy noop version to prevent errors
38645   self.ngModelCtrl = noopNgModelController;
38646
38647   // The "unknown" option is one that is prepended to the list if the viewValue
38648   // does not match any of the options. When it is rendered the value of the unknown
38649   // option is '? XXX ?' where XXX is the hashKey of the value that is not known.
38650   //
38651   // We can't just jqLite('<option>') since jqLite is not smart enough
38652   // to create it in <select> and IE barfs otherwise.
38653   self.unknownOption = jqLite(document.createElement('option'));
38654   self.renderUnknownOption = function(val) {
38655     var unknownVal = '? ' + hashKey(val) + ' ?';
38656     self.unknownOption.val(unknownVal);
38657     $element.prepend(self.unknownOption);
38658     $element.val(unknownVal);
38659   };
38660
38661   $scope.$on('$destroy', function() {
38662     // disable unknown option so that we don't do work when the whole select is being destroyed
38663     self.renderUnknownOption = noop;
38664   });
38665
38666   self.removeUnknownOption = function() {
38667     if (self.unknownOption.parent()) self.unknownOption.remove();
38668   };
38669
38670
38671   // Read the value of the select control, the implementation of this changes depending
38672   // upon whether the select can have multiple values and whether ngOptions is at work.
38673   self.readValue = function readSingleValue() {
38674     self.removeUnknownOption();
38675     return $element.val();
38676   };
38677
38678
38679   // Write the value to the select control, the implementation of this changes depending
38680   // upon whether the select can have multiple values and whether ngOptions is at work.
38681   self.writeValue = function writeSingleValue(value) {
38682     if (self.hasOption(value)) {
38683       self.removeUnknownOption();
38684       $element.val(value);
38685       if (value === '') self.emptyOption.prop('selected', true); // to make IE9 happy
38686     } else {
38687       if (value == null && self.emptyOption) {
38688         self.removeUnknownOption();
38689         $element.val('');
38690       } else {
38691         self.renderUnknownOption(value);
38692       }
38693     }
38694   };
38695
38696
38697   // Tell the select control that an option, with the given value, has been added
38698   self.addOption = function(value, element) {
38699     // Skip comment nodes, as they only pollute the `optionsMap`
38700     if (element[0].nodeType === NODE_TYPE_COMMENT) return;
38701
38702     assertNotHasOwnProperty(value, '"option value"');
38703     if (value === '') {
38704       self.emptyOption = element;
38705     }
38706     var count = optionsMap.get(value) || 0;
38707     optionsMap.put(value, count + 1);
38708     self.ngModelCtrl.$render();
38709     chromeHack(element);
38710   };
38711
38712   // Tell the select control that an option, with the given value, has been removed
38713   self.removeOption = function(value) {
38714     var count = optionsMap.get(value);
38715     if (count) {
38716       if (count === 1) {
38717         optionsMap.remove(value);
38718         if (value === '') {
38719           self.emptyOption = undefined;
38720         }
38721       } else {
38722         optionsMap.put(value, count - 1);
38723       }
38724     }
38725   };
38726
38727   // Check whether the select control has an option matching the given value
38728   self.hasOption = function(value) {
38729     return !!optionsMap.get(value);
38730   };
38731
38732
38733   self.registerOption = function(optionScope, optionElement, optionAttrs, interpolateValueFn, interpolateTextFn) {
38734
38735     if (interpolateValueFn) {
38736       // The value attribute is interpolated
38737       var oldVal;
38738       optionAttrs.$observe('value', function valueAttributeObserveAction(newVal) {
38739         if (isDefined(oldVal)) {
38740           self.removeOption(oldVal);
38741         }
38742         oldVal = newVal;
38743         self.addOption(newVal, optionElement);
38744       });
38745     } else if (interpolateTextFn) {
38746       // The text content is interpolated
38747       optionScope.$watch(interpolateTextFn, function interpolateWatchAction(newVal, oldVal) {
38748         optionAttrs.$set('value', newVal);
38749         if (oldVal !== newVal) {
38750           self.removeOption(oldVal);
38751         }
38752         self.addOption(newVal, optionElement);
38753       });
38754     } else {
38755       // The value attribute is static
38756       self.addOption(optionAttrs.value, optionElement);
38757     }
38758
38759     optionElement.on('$destroy', function() {
38760       self.removeOption(optionAttrs.value);
38761       self.ngModelCtrl.$render();
38762     });
38763   };
38764 }];
38765
38766 /**
38767  * @ngdoc directive
38768  * @name select
38769  * @restrict E
38770  *
38771  * @description
38772  * HTML `SELECT` element with angular data-binding.
38773  *
38774  * The `select` directive is used together with {@link ngModel `ngModel`} to provide data-binding
38775  * between the scope and the `<select>` control (including setting default values).
38776  * It also handles dynamic `<option>` elements, which can be added using the {@link ngRepeat `ngRepeat}` or
38777  * {@link ngOptions `ngOptions`} directives.
38778  *
38779  * When an item in the `<select>` menu is selected, the value of the selected option will be bound
38780  * to the model identified by the `ngModel` directive. With static or repeated options, this is
38781  * the content of the `value` attribute or the textContent of the `<option>`, if the value attribute is missing.
38782  * If you want dynamic value attributes, you can use interpolation inside the value attribute.
38783  *
38784  * <div class="alert alert-warning">
38785  * Note that the value of a `select` directive used without `ngOptions` is always a string.
38786  * When the model needs to be bound to a non-string value, you must either explicitly convert it
38787  * using a directive (see example below) or use `ngOptions` to specify the set of options.
38788  * This is because an option element can only be bound to string values at present.
38789  * </div>
38790  *
38791  * If the viewValue of `ngModel` does not match any of the options, then the control
38792  * will automatically add an "unknown" option, which it then removes when the mismatch is resolved.
38793  *
38794  * Optionally, a single hard-coded `<option>` element, with the value set to an empty string, can
38795  * be nested into the `<select>` element. This element will then represent the `null` or "not selected"
38796  * option. See example below for demonstration.
38797  *
38798  * <div class="alert alert-info">
38799  * In many cases, `ngRepeat` can be used on `<option>` elements instead of {@link ng.directive:ngOptions
38800  * ngOptions} to achieve a similar result. However, `ngOptions` provides some benefits, such as
38801  * more flexibility in how the `<select>`'s model is assigned via the `select` **`as`** part of the
38802  * comprehension expression, and additionally in reducing memory and increasing speed by not creating
38803  * a new scope for each repeated instance.
38804  * </div>
38805  *
38806  *
38807  * @param {string} ngModel Assignable angular expression to data-bind to.
38808  * @param {string=} name Property name of the form under which the control is published.
38809  * @param {string=} multiple Allows multiple options to be selected. The selected values will be
38810  *     bound to the model as an array.
38811  * @param {string=} required Sets `required` validation error key if the value is not entered.
38812  * @param {string=} ngRequired Adds required attribute and required validation constraint to
38813  * the element when the ngRequired expression evaluates to true. Use ngRequired instead of required
38814  * when you want to data-bind to the required attribute.
38815  * @param {string=} ngChange Angular expression to be executed when selected option(s) changes due to user
38816  *    interaction with the select element.
38817  * @param {string=} ngOptions sets the options that the select is populated with and defines what is
38818  * set on the model on selection. See {@link ngOptions `ngOptions`}.
38819  *
38820  * @example
38821  * ### Simple `select` elements with static options
38822  *
38823  * <example name="static-select" module="staticSelect">
38824  * <file name="index.html">
38825  * <div ng-controller="ExampleController">
38826  *   <form name="myForm">
38827  *     <label for="singleSelect"> Single select: </label><br>
38828  *     <select name="singleSelect" ng-model="data.singleSelect">
38829  *       <option value="option-1">Option 1</option>
38830  *       <option value="option-2">Option 2</option>
38831  *     </select><br>
38832  *
38833  *     <label for="singleSelect"> Single select with "not selected" option and dynamic option values: </label><br>
38834  *     <select name="singleSelect" id="singleSelect" ng-model="data.singleSelect">
38835  *       <option value="">---Please select---</option> <!-- not selected / blank option -->
38836  *       <option value="{{data.option1}}">Option 1</option> <!-- interpolation -->
38837  *       <option value="option-2">Option 2</option>
38838  *     </select><br>
38839  *     <button ng-click="forceUnknownOption()">Force unknown option</button><br>
38840  *     <tt>singleSelect = {{data.singleSelect}}</tt>
38841  *
38842  *     <hr>
38843  *     <label for="multipleSelect"> Multiple select: </label><br>
38844  *     <select name="multipleSelect" id="multipleSelect" ng-model="data.multipleSelect" multiple>
38845  *       <option value="option-1">Option 1</option>
38846  *       <option value="option-2">Option 2</option>
38847  *       <option value="option-3">Option 3</option>
38848  *     </select><br>
38849  *     <tt>multipleSelect = {{data.multipleSelect}}</tt><br/>
38850  *   </form>
38851  * </div>
38852  * </file>
38853  * <file name="app.js">
38854  *  angular.module('staticSelect', [])
38855  *    .controller('ExampleController', ['$scope', function($scope) {
38856  *      $scope.data = {
38857  *       singleSelect: null,
38858  *       multipleSelect: [],
38859  *       option1: 'option-1',
38860  *      };
38861  *
38862  *      $scope.forceUnknownOption = function() {
38863  *        $scope.data.singleSelect = 'nonsense';
38864  *      };
38865  *   }]);
38866  * </file>
38867  *</example>
38868  *
38869  * ### Using `ngRepeat` to generate `select` options
38870  * <example name="ngrepeat-select" module="ngrepeatSelect">
38871  * <file name="index.html">
38872  * <div ng-controller="ExampleController">
38873  *   <form name="myForm">
38874  *     <label for="repeatSelect"> Repeat select: </label>
38875  *     <select name="repeatSelect" id="repeatSelect" ng-model="data.repeatSelect">
38876  *       <option ng-repeat="option in data.availableOptions" value="{{option.id}}">{{option.name}}</option>
38877  *     </select>
38878  *   </form>
38879  *   <hr>
38880  *   <tt>repeatSelect = {{data.repeatSelect}}</tt><br/>
38881  * </div>
38882  * </file>
38883  * <file name="app.js">
38884  *  angular.module('ngrepeatSelect', [])
38885  *    .controller('ExampleController', ['$scope', function($scope) {
38886  *      $scope.data = {
38887  *       repeatSelect: null,
38888  *       availableOptions: [
38889  *         {id: '1', name: 'Option A'},
38890  *         {id: '2', name: 'Option B'},
38891  *         {id: '3', name: 'Option C'}
38892  *       ],
38893  *      };
38894  *   }]);
38895  * </file>
38896  *</example>
38897  *
38898  *
38899  * ### Using `select` with `ngOptions` and setting a default value
38900  * See the {@link ngOptions ngOptions documentation} for more `ngOptions` usage examples.
38901  *
38902  * <example name="select-with-default-values" module="defaultValueSelect">
38903  * <file name="index.html">
38904  * <div ng-controller="ExampleController">
38905  *   <form name="myForm">
38906  *     <label for="mySelect">Make a choice:</label>
38907  *     <select name="mySelect" id="mySelect"
38908  *       ng-options="option.name for option in data.availableOptions track by option.id"
38909  *       ng-model="data.selectedOption"></select>
38910  *   </form>
38911  *   <hr>
38912  *   <tt>option = {{data.selectedOption}}</tt><br/>
38913  * </div>
38914  * </file>
38915  * <file name="app.js">
38916  *  angular.module('defaultValueSelect', [])
38917  *    .controller('ExampleController', ['$scope', function($scope) {
38918  *      $scope.data = {
38919  *       availableOptions: [
38920  *         {id: '1', name: 'Option A'},
38921  *         {id: '2', name: 'Option B'},
38922  *         {id: '3', name: 'Option C'}
38923  *       ],
38924  *       selectedOption: {id: '3', name: 'Option C'} //This sets the default value of the select in the ui
38925  *       };
38926  *   }]);
38927  * </file>
38928  *</example>
38929  *
38930  *
38931  * ### Binding `select` to a non-string value via `ngModel` parsing / formatting
38932  *
38933  * <example name="select-with-non-string-options" module="nonStringSelect">
38934  *   <file name="index.html">
38935  *     <select ng-model="model.id" convert-to-number>
38936  *       <option value="0">Zero</option>
38937  *       <option value="1">One</option>
38938  *       <option value="2">Two</option>
38939  *     </select>
38940  *     {{ model }}
38941  *   </file>
38942  *   <file name="app.js">
38943  *     angular.module('nonStringSelect', [])
38944  *       .run(function($rootScope) {
38945  *         $rootScope.model = { id: 2 };
38946  *       })
38947  *       .directive('convertToNumber', function() {
38948  *         return {
38949  *           require: 'ngModel',
38950  *           link: function(scope, element, attrs, ngModel) {
38951  *             ngModel.$parsers.push(function(val) {
38952  *               return parseInt(val, 10);
38953  *             });
38954  *             ngModel.$formatters.push(function(val) {
38955  *               return '' + val;
38956  *             });
38957  *           }
38958  *         };
38959  *       });
38960  *   </file>
38961  *   <file name="protractor.js" type="protractor">
38962  *     it('should initialize to model', function() {
38963  *       var select = element(by.css('select'));
38964  *       expect(element(by.model('model.id')).$('option:checked').getText()).toEqual('Two');
38965  *     });
38966  *   </file>
38967  * </example>
38968  *
38969  */
38970 var selectDirective = function() {
38971
38972   return {
38973     restrict: 'E',
38974     require: ['select', '?ngModel'],
38975     controller: SelectController,
38976     priority: 1,
38977     link: {
38978       pre: selectPreLink,
38979       post: selectPostLink
38980     }
38981   };
38982
38983   function selectPreLink(scope, element, attr, ctrls) {
38984
38985       // if ngModel is not defined, we don't need to do anything
38986       var ngModelCtrl = ctrls[1];
38987       if (!ngModelCtrl) return;
38988
38989       var selectCtrl = ctrls[0];
38990
38991       selectCtrl.ngModelCtrl = ngModelCtrl;
38992
38993       // When the selected item(s) changes we delegate getting the value of the select control
38994       // to the `readValue` method, which can be changed if the select can have multiple
38995       // selected values or if the options are being generated by `ngOptions`
38996       element.on('change', function() {
38997         scope.$apply(function() {
38998           ngModelCtrl.$setViewValue(selectCtrl.readValue());
38999         });
39000       });
39001
39002       // If the select allows multiple values then we need to modify how we read and write
39003       // values from and to the control; also what it means for the value to be empty and
39004       // we have to add an extra watch since ngModel doesn't work well with arrays - it
39005       // doesn't trigger rendering if only an item in the array changes.
39006       if (attr.multiple) {
39007
39008         // Read value now needs to check each option to see if it is selected
39009         selectCtrl.readValue = function readMultipleValue() {
39010           var array = [];
39011           forEach(element.find('option'), function(option) {
39012             if (option.selected) {
39013               array.push(option.value);
39014             }
39015           });
39016           return array;
39017         };
39018
39019         // Write value now needs to set the selected property of each matching option
39020         selectCtrl.writeValue = function writeMultipleValue(value) {
39021           var items = new HashMap(value);
39022           forEach(element.find('option'), function(option) {
39023             option.selected = isDefined(items.get(option.value));
39024           });
39025         };
39026
39027         // we have to do it on each watch since ngModel watches reference, but
39028         // we need to work of an array, so we need to see if anything was inserted/removed
39029         var lastView, lastViewRef = NaN;
39030         scope.$watch(function selectMultipleWatch() {
39031           if (lastViewRef === ngModelCtrl.$viewValue && !equals(lastView, ngModelCtrl.$viewValue)) {
39032             lastView = shallowCopy(ngModelCtrl.$viewValue);
39033             ngModelCtrl.$render();
39034           }
39035           lastViewRef = ngModelCtrl.$viewValue;
39036         });
39037
39038         // If we are a multiple select then value is now a collection
39039         // so the meaning of $isEmpty changes
39040         ngModelCtrl.$isEmpty = function(value) {
39041           return !value || value.length === 0;
39042         };
39043
39044       }
39045     }
39046
39047     function selectPostLink(scope, element, attrs, ctrls) {
39048       // if ngModel is not defined, we don't need to do anything
39049       var ngModelCtrl = ctrls[1];
39050       if (!ngModelCtrl) return;
39051
39052       var selectCtrl = ctrls[0];
39053
39054       // We delegate rendering to the `writeValue` method, which can be changed
39055       // if the select can have multiple selected values or if the options are being
39056       // generated by `ngOptions`.
39057       // This must be done in the postLink fn to prevent $render to be called before
39058       // all nodes have been linked correctly.
39059       ngModelCtrl.$render = function() {
39060         selectCtrl.writeValue(ngModelCtrl.$viewValue);
39061       };
39062     }
39063 };
39064
39065
39066 // The option directive is purely designed to communicate the existence (or lack of)
39067 // of dynamically created (and destroyed) option elements to their containing select
39068 // directive via its controller.
39069 var optionDirective = ['$interpolate', function($interpolate) {
39070   return {
39071     restrict: 'E',
39072     priority: 100,
39073     compile: function(element, attr) {
39074       if (isDefined(attr.value)) {
39075         // If the value attribute is defined, check if it contains an interpolation
39076         var interpolateValueFn = $interpolate(attr.value, true);
39077       } else {
39078         // If the value attribute is not defined then we fall back to the
39079         // text content of the option element, which may be interpolated
39080         var interpolateTextFn = $interpolate(element.text(), true);
39081         if (!interpolateTextFn) {
39082           attr.$set('value', element.text());
39083         }
39084       }
39085
39086       return function(scope, element, attr) {
39087         // This is an optimization over using ^^ since we don't want to have to search
39088         // all the way to the root of the DOM for every single option element
39089         var selectCtrlName = '$selectController',
39090             parent = element.parent(),
39091             selectCtrl = parent.data(selectCtrlName) ||
39092               parent.parent().data(selectCtrlName); // in case we are in optgroup
39093
39094         if (selectCtrl) {
39095           selectCtrl.registerOption(scope, element, attr, interpolateValueFn, interpolateTextFn);
39096         }
39097       };
39098     }
39099   };
39100 }];
39101
39102 var styleDirective = valueFn({
39103   restrict: 'E',
39104   terminal: false
39105 });
39106
39107 /**
39108  * @ngdoc directive
39109  * @name ngRequired
39110  *
39111  * @description
39112  *
39113  * ngRequired adds the required {@link ngModel.NgModelController#$validators `validator`} to {@link ngModel `ngModel`}.
39114  * It is most often used for {@link input `input`} and {@link select `select`} controls, but can also be
39115  * applied to custom controls.
39116  *
39117  * The directive sets the `required` attribute on the element if the Angular expression inside
39118  * `ngRequired` evaluates to true. A special directive for setting `required` is necessary because we
39119  * cannot use interpolation inside `required`. See the {@link guide/interpolation interpolation guide}
39120  * for more info.
39121  *
39122  * The validator will set the `required` error key to true if the `required` attribute is set and
39123  * calling {@link ngModel.NgModelController#$isEmpty `NgModelController.$isEmpty`} with the
39124  * {@link ngModel.NgModelController#$viewValue `ngModel.$viewValue`} returns `true`. For example, the
39125  * `$isEmpty()` implementation for `input[text]` checks the length of the `$viewValue`. When developing
39126  * custom controls, `$isEmpty()` can be overwritten to account for a $viewValue that is not string-based.
39127  *
39128  * @example
39129  * <example name="ngRequiredDirective" module="ngRequiredExample">
39130  *   <file name="index.html">
39131  *     <script>
39132  *       angular.module('ngRequiredExample', [])
39133  *         .controller('ExampleController', ['$scope', function($scope) {
39134  *           $scope.required = true;
39135  *         }]);
39136  *     </script>
39137  *     <div ng-controller="ExampleController">
39138  *       <form name="form">
39139  *         <label for="required">Toggle required: </label>
39140  *         <input type="checkbox" ng-model="required" id="required" />
39141  *         <br>
39142  *         <label for="input">This input must be filled if `required` is true: </label>
39143  *         <input type="text" ng-model="model" id="input" name="input" ng-required="required" /><br>
39144  *         <hr>
39145  *         required error set? = <code>{{form.input.$error.required}}</code><br>
39146  *         model = <code>{{model}}</code>
39147  *       </form>
39148  *     </div>
39149  *   </file>
39150  *   <file name="protractor.js" type="protractor">
39151        var required = element(by.binding('form.input.$error.required'));
39152        var model = element(by.binding('model'));
39153        var input = element(by.id('input'));
39154
39155        it('should set the required error', function() {
39156          expect(required.getText()).toContain('true');
39157
39158          input.sendKeys('123');
39159          expect(required.getText()).not.toContain('true');
39160          expect(model.getText()).toContain('123');
39161        });
39162  *   </file>
39163  * </example>
39164  */
39165 var requiredDirective = function() {
39166   return {
39167     restrict: 'A',
39168     require: '?ngModel',
39169     link: function(scope, elm, attr, ctrl) {
39170       if (!ctrl) return;
39171       attr.required = true; // force truthy in case we are on non input element
39172
39173       ctrl.$validators.required = function(modelValue, viewValue) {
39174         return !attr.required || !ctrl.$isEmpty(viewValue);
39175       };
39176
39177       attr.$observe('required', function() {
39178         ctrl.$validate();
39179       });
39180     }
39181   };
39182 };
39183
39184 /**
39185  * @ngdoc directive
39186  * @name ngPattern
39187  *
39188  * @description
39189  *
39190  * ngPattern adds the pattern {@link ngModel.NgModelController#$validators `validator`} to {@link ngModel `ngModel`}.
39191  * It is most often used for text-based {@link input `input`} controls, but can also be applied to custom text-based controls.
39192  *
39193  * The validator sets the `pattern` error key if the {@link ngModel.NgModelController#$viewValue `ngModel.$viewValue`}
39194  * does not match a RegExp which is obtained by evaluating the Angular expression given in the
39195  * `ngPattern` attribute value:
39196  * * If the expression evaluates to a RegExp object, then this is used directly.
39197  * * If the expression evaluates to a string, then it will be converted to a RegExp after wrapping it
39198  * in `^` and `$` characters. For instance, `"abc"` will be converted to `new RegExp('^abc$')`.
39199  *
39200  * <div class="alert alert-info">
39201  * **Note:** Avoid using the `g` flag on the RegExp, as it will cause each successive search to
39202  * start at the index of the last search's match, thus not taking the whole input value into
39203  * account.
39204  * </div>
39205  *
39206  * <div class="alert alert-info">
39207  * **Note:** This directive is also added when the plain `pattern` attribute is used, with two
39208  * differences:
39209  * <ol>
39210  *   <li>
39211  *     `ngPattern` does not set the `pattern` attribute and therefore HTML5 constraint validation is
39212  *     not available.
39213  *   </li>
39214  *   <li>
39215  *     The `ngPattern` attribute must be an expression, while the `pattern` value must be
39216  *     interpolated.
39217  *   </li>
39218  * </ol>
39219  * </div>
39220  *
39221  * @example
39222  * <example name="ngPatternDirective" module="ngPatternExample">
39223  *   <file name="index.html">
39224  *     <script>
39225  *       angular.module('ngPatternExample', [])
39226  *         .controller('ExampleController', ['$scope', function($scope) {
39227  *           $scope.regex = '\\d+';
39228  *         }]);
39229  *     </script>
39230  *     <div ng-controller="ExampleController">
39231  *       <form name="form">
39232  *         <label for="regex">Set a pattern (regex string): </label>
39233  *         <input type="text" ng-model="regex" id="regex" />
39234  *         <br>
39235  *         <label for="input">This input is restricted by the current pattern: </label>
39236  *         <input type="text" ng-model="model" id="input" name="input" ng-pattern="regex" /><br>
39237  *         <hr>
39238  *         input valid? = <code>{{form.input.$valid}}</code><br>
39239  *         model = <code>{{model}}</code>
39240  *       </form>
39241  *     </div>
39242  *   </file>
39243  *   <file name="protractor.js" type="protractor">
39244        var model = element(by.binding('model'));
39245        var input = element(by.id('input'));
39246
39247        it('should validate the input with the default pattern', function() {
39248          input.sendKeys('aaa');
39249          expect(model.getText()).not.toContain('aaa');
39250
39251          input.clear().then(function() {
39252            input.sendKeys('123');
39253            expect(model.getText()).toContain('123');
39254          });
39255        });
39256  *   </file>
39257  * </example>
39258  */
39259 var patternDirective = function() {
39260   return {
39261     restrict: 'A',
39262     require: '?ngModel',
39263     link: function(scope, elm, attr, ctrl) {
39264       if (!ctrl) return;
39265
39266       var regexp, patternExp = attr.ngPattern || attr.pattern;
39267       attr.$observe('pattern', function(regex) {
39268         if (isString(regex) && regex.length > 0) {
39269           regex = new RegExp('^' + regex + '$');
39270         }
39271
39272         if (regex && !regex.test) {
39273           throw minErr('ngPattern')('noregexp',
39274             'Expected {0} to be a RegExp but was {1}. Element: {2}', patternExp,
39275             regex, startingTag(elm));
39276         }
39277
39278         regexp = regex || undefined;
39279         ctrl.$validate();
39280       });
39281
39282       ctrl.$validators.pattern = function(modelValue, viewValue) {
39283         // HTML5 pattern constraint validates the input value, so we validate the viewValue
39284         return ctrl.$isEmpty(viewValue) || isUndefined(regexp) || regexp.test(viewValue);
39285       };
39286     }
39287   };
39288 };
39289
39290 /**
39291  * @ngdoc directive
39292  * @name ngMaxlength
39293  *
39294  * @description
39295  *
39296  * ngMaxlength adds the maxlength {@link ngModel.NgModelController#$validators `validator`} to {@link ngModel `ngModel`}.
39297  * It is most often used for text-based {@link input `input`} controls, but can also be applied to custom text-based controls.
39298  *
39299  * The validator sets the `maxlength` error key if the {@link ngModel.NgModelController#$viewValue `ngModel.$viewValue`}
39300  * is longer than the integer obtained by evaluating the Angular expression given in the
39301  * `ngMaxlength` attribute value.
39302  *
39303  * <div class="alert alert-info">
39304  * **Note:** This directive is also added when the plain `maxlength` attribute is used, with two
39305  * differences:
39306  * <ol>
39307  *   <li>
39308  *     `ngMaxlength` does not set the `maxlength` attribute and therefore HTML5 constraint
39309  *     validation is not available.
39310  *   </li>
39311  *   <li>
39312  *     The `ngMaxlength` attribute must be an expression, while the `maxlength` value must be
39313  *     interpolated.
39314  *   </li>
39315  * </ol>
39316  * </div>
39317  *
39318  * @example
39319  * <example name="ngMaxlengthDirective" module="ngMaxlengthExample">
39320  *   <file name="index.html">
39321  *     <script>
39322  *       angular.module('ngMaxlengthExample', [])
39323  *         .controller('ExampleController', ['$scope', function($scope) {
39324  *           $scope.maxlength = 5;
39325  *         }]);
39326  *     </script>
39327  *     <div ng-controller="ExampleController">
39328  *       <form name="form">
39329  *         <label for="maxlength">Set a maxlength: </label>
39330  *         <input type="number" ng-model="maxlength" id="maxlength" />
39331  *         <br>
39332  *         <label for="input">This input is restricted by the current maxlength: </label>
39333  *         <input type="text" ng-model="model" id="input" name="input" ng-maxlength="maxlength" /><br>
39334  *         <hr>
39335  *         input valid? = <code>{{form.input.$valid}}</code><br>
39336  *         model = <code>{{model}}</code>
39337  *       </form>
39338  *     </div>
39339  *   </file>
39340  *   <file name="protractor.js" type="protractor">
39341        var model = element(by.binding('model'));
39342        var input = element(by.id('input'));
39343
39344        it('should validate the input with the default maxlength', function() {
39345          input.sendKeys('abcdef');
39346          expect(model.getText()).not.toContain('abcdef');
39347
39348          input.clear().then(function() {
39349            input.sendKeys('abcde');
39350            expect(model.getText()).toContain('abcde');
39351          });
39352        });
39353  *   </file>
39354  * </example>
39355  */
39356 var maxlengthDirective = function() {
39357   return {
39358     restrict: 'A',
39359     require: '?ngModel',
39360     link: function(scope, elm, attr, ctrl) {
39361       if (!ctrl) return;
39362
39363       var maxlength = -1;
39364       attr.$observe('maxlength', function(value) {
39365         var intVal = toInt(value);
39366         maxlength = isNaN(intVal) ? -1 : intVal;
39367         ctrl.$validate();
39368       });
39369       ctrl.$validators.maxlength = function(modelValue, viewValue) {
39370         return (maxlength < 0) || ctrl.$isEmpty(viewValue) || (viewValue.length <= maxlength);
39371       };
39372     }
39373   };
39374 };
39375
39376 /**
39377  * @ngdoc directive
39378  * @name ngMinlength
39379  *
39380  * @description
39381  *
39382  * ngMinlength adds the minlength {@link ngModel.NgModelController#$validators `validator`} to {@link ngModel `ngModel`}.
39383  * It is most often used for text-based {@link input `input`} controls, but can also be applied to custom text-based controls.
39384  *
39385  * The validator sets the `minlength` error key if the {@link ngModel.NgModelController#$viewValue `ngModel.$viewValue`}
39386  * is shorter than the integer obtained by evaluating the Angular expression given in the
39387  * `ngMinlength` attribute value.
39388  *
39389  * <div class="alert alert-info">
39390  * **Note:** This directive is also added when the plain `minlength` attribute is used, with two
39391  * differences:
39392  * <ol>
39393  *   <li>
39394  *     `ngMinlength` does not set the `minlength` attribute and therefore HTML5 constraint
39395  *     validation is not available.
39396  *   </li>
39397  *   <li>
39398  *     The `ngMinlength` value must be an expression, while the `minlength` value must be
39399  *     interpolated.
39400  *   </li>
39401  * </ol>
39402  * </div>
39403  *
39404  * @example
39405  * <example name="ngMinlengthDirective" module="ngMinlengthExample">
39406  *   <file name="index.html">
39407  *     <script>
39408  *       angular.module('ngMinlengthExample', [])
39409  *         .controller('ExampleController', ['$scope', function($scope) {
39410  *           $scope.minlength = 3;
39411  *         }]);
39412  *     </script>
39413  *     <div ng-controller="ExampleController">
39414  *       <form name="form">
39415  *         <label for="minlength">Set a minlength: </label>
39416  *         <input type="number" ng-model="minlength" id="minlength" />
39417  *         <br>
39418  *         <label for="input">This input is restricted by the current minlength: </label>
39419  *         <input type="text" ng-model="model" id="input" name="input" ng-minlength="minlength" /><br>
39420  *         <hr>
39421  *         input valid? = <code>{{form.input.$valid}}</code><br>
39422  *         model = <code>{{model}}</code>
39423  *       </form>
39424  *     </div>
39425  *   </file>
39426  *   <file name="protractor.js" type="protractor">
39427        var model = element(by.binding('model'));
39428        var input = element(by.id('input'));
39429
39430        it('should validate the input with the default minlength', function() {
39431          input.sendKeys('ab');
39432          expect(model.getText()).not.toContain('ab');
39433
39434          input.sendKeys('abc');
39435          expect(model.getText()).toContain('abc');
39436        });
39437  *   </file>
39438  * </example>
39439  */
39440 var minlengthDirective = function() {
39441   return {
39442     restrict: 'A',
39443     require: '?ngModel',
39444     link: function(scope, elm, attr, ctrl) {
39445       if (!ctrl) return;
39446
39447       var minlength = 0;
39448       attr.$observe('minlength', function(value) {
39449         minlength = toInt(value) || 0;
39450         ctrl.$validate();
39451       });
39452       ctrl.$validators.minlength = function(modelValue, viewValue) {
39453         return ctrl.$isEmpty(viewValue) || viewValue.length >= minlength;
39454       };
39455     }
39456   };
39457 };
39458
39459 if (window.angular.bootstrap) {
39460   //AngularJS is already loaded, so we can return here...
39461   console.log('WARNING: Tried to load angular more than once.');
39462   return;
39463 }
39464
39465 //try to bind to jquery now so that one can write jqLite(document).ready()
39466 //but we will rebind on bootstrap again.
39467 bindJQuery();
39468
39469 publishExternalAPI(angular);
39470
39471 angular.module("ngLocale", [], ["$provide", function($provide) {
39472 var PLURAL_CATEGORY = {ZERO: "zero", ONE: "one", TWO: "two", FEW: "few", MANY: "many", OTHER: "other"};
39473 function getDecimals(n) {
39474   n = n + '';
39475   var i = n.indexOf('.');
39476   return (i == -1) ? 0 : n.length - i - 1;
39477 }
39478
39479 function getVF(n, opt_precision) {
39480   var v = opt_precision;
39481
39482   if (undefined === v) {
39483     v = Math.min(getDecimals(n), 3);
39484   }
39485
39486   var base = Math.pow(10, v);
39487   var f = ((n * base) | 0) % base;
39488   return {v: v, f: f};
39489 }
39490
39491 $provide.value("$locale", {
39492   "DATETIME_FORMATS": {
39493     "AMPMS": [
39494       "AM",
39495       "PM"
39496     ],
39497     "DAY": [
39498       "Sunday",
39499       "Monday",
39500       "Tuesday",
39501       "Wednesday",
39502       "Thursday",
39503       "Friday",
39504       "Saturday"
39505     ],
39506     "ERANAMES": [
39507       "Before Christ",
39508       "Anno Domini"
39509     ],
39510     "ERAS": [
39511       "BC",
39512       "AD"
39513     ],
39514     "FIRSTDAYOFWEEK": 6,
39515     "MONTH": [
39516       "January",
39517       "February",
39518       "March",
39519       "April",
39520       "May",
39521       "June",
39522       "July",
39523       "August",
39524       "September",
39525       "October",
39526       "November",
39527       "December"
39528     ],
39529     "SHORTDAY": [
39530       "Sun",
39531       "Mon",
39532       "Tue",
39533       "Wed",
39534       "Thu",
39535       "Fri",
39536       "Sat"
39537     ],
39538     "SHORTMONTH": [
39539       "Jan",
39540       "Feb",
39541       "Mar",
39542       "Apr",
39543       "May",
39544       "Jun",
39545       "Jul",
39546       "Aug",
39547       "Sep",
39548       "Oct",
39549       "Nov",
39550       "Dec"
39551     ],
39552     "STANDALONEMONTH": [
39553       "January",
39554       "February",
39555       "March",
39556       "April",
39557       "May",
39558       "June",
39559       "July",
39560       "August",
39561       "September",
39562       "October",
39563       "November",
39564       "December"
39565     ],
39566     "WEEKENDRANGE": [
39567       5,
39568       6
39569     ],
39570     "fullDate": "EEEE, MMMM d, y",
39571     "longDate": "MMMM d, y",
39572     "medium": "MMM d, y h:mm:ss a",
39573     "mediumDate": "MMM d, y",
39574     "mediumTime": "h:mm:ss a",
39575     "short": "M/d/yy h:mm a",
39576     "shortDate": "M/d/yy",
39577     "shortTime": "h:mm a"
39578   },
39579   "NUMBER_FORMATS": {
39580     "CURRENCY_SYM": "$",
39581     "DECIMAL_SEP": ".",
39582     "GROUP_SEP": ",",
39583     "PATTERNS": [
39584       {
39585         "gSize": 3,
39586         "lgSize": 3,
39587         "maxFrac": 3,
39588         "minFrac": 0,
39589         "minInt": 1,
39590         "negPre": "-",
39591         "negSuf": "",
39592         "posPre": "",
39593         "posSuf": ""
39594       },
39595       {
39596         "gSize": 3,
39597         "lgSize": 3,
39598         "maxFrac": 2,
39599         "minFrac": 2,
39600         "minInt": 1,
39601         "negPre": "-\u00a4",
39602         "negSuf": "",
39603         "posPre": "\u00a4",
39604         "posSuf": ""
39605       }
39606     ]
39607   },
39608   "id": "en-us",
39609   "localeID": "en_US",
39610   "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;}
39611 });
39612 }]);
39613
39614 /**
39615  * Setup file for the Scenario.
39616  * Must be first in the compilation/bootstrap list.
39617  */
39618
39619 // Public namespace
39620 angular.scenario = angular.scenario || {};
39621
39622 /**
39623  * Expose jQuery (e.g. for custom dsl extensions).
39624  */
39625 angular.scenario.jQuery = _jQuery;
39626
39627 /**
39628  * Defines a new output format.
39629  *
39630  * @param {string} name the name of the new output format
39631  * @param {function()} fn function(context, runner) that generates the output
39632  */
39633 angular.scenario.output = angular.scenario.output || function(name, fn) {
39634   angular.scenario.output[name] = fn;
39635 };
39636
39637 /**
39638  * Defines a new DSL statement. If your factory function returns a Future
39639  * it's returned, otherwise the result is assumed to be a map of functions
39640  * for chaining. Chained functions are subject to the same rules.
39641  *
39642  * Note: All functions on the chain are bound to the chain scope so values
39643  *   set on "this" in your statement function are available in the chained
39644  *   functions.
39645  *
39646  * @param {string} name The name of the statement
39647  * @param {function()} fn Factory function(), return a function for
39648  *  the statement.
39649  */
39650 angular.scenario.dsl = angular.scenario.dsl || function(name, fn) {
39651   angular.scenario.dsl[name] = function() {
39652     /* jshint -W040 *//* The dsl binds `this` for us when calling chained functions */
39653     function executeStatement(statement, args) {
39654       var result = statement.apply(this, args);
39655       if (angular.isFunction(result) || result instanceof angular.scenario.Future) {
39656         return result;
39657       }
39658       var self = this;
39659       var chain = angular.extend({}, result);
39660       angular.forEach(chain, function(value, name) {
39661         if (angular.isFunction(value)) {
39662           chain[name] = function() {
39663             return executeStatement.call(self, value, arguments);
39664           };
39665         } else {
39666           chain[name] = value;
39667         }
39668       });
39669       return chain;
39670     }
39671     var statement = fn.apply(this, arguments);
39672     return function() {
39673       return executeStatement.call(this, statement, arguments);
39674     };
39675   };
39676 };
39677
39678 /**
39679  * Defines a new matcher for use with the expects() statement. The value
39680  * this.actual (like in Jasmine) is available in your matcher to compare
39681  * against. Your function should return a boolean. The future is automatically
39682  * created for you.
39683  *
39684  * @param {string} name The name of the matcher
39685  * @param {function()} fn The matching function(expected).
39686  */
39687 angular.scenario.matcher = angular.scenario.matcher || function(name, fn) {
39688   angular.scenario.matcher[name] = function(expected) {
39689     var description = this.future.name +
39690                       (this.inverse ? ' not ' : ' ') + name +
39691                       ' ' + angular.toJson(expected);
39692     var self = this;
39693     this.addFuture('expect ' + description,
39694       function(done) {
39695         var error;
39696         self.actual = self.future.value;
39697         if ((self.inverse && fn.call(self, expected)) ||
39698             (!self.inverse && !fn.call(self, expected))) {
39699           error = 'expected ' + description +
39700             ' but was ' + angular.toJson(self.actual);
39701         }
39702         done(error);
39703     });
39704   };
39705 };
39706
39707 /**
39708  * Initialize the scenario runner and run !
39709  *
39710  * Access global window and document object
39711  * Access $runner through closure
39712  *
39713  * @param {Object=} config Config options
39714  */
39715 angular.scenario.setUpAndRun = function(config) {
39716   var href = window.location.href;
39717   var body = _jQuery(document.body);
39718   var output = [];
39719   var objModel = new angular.scenario.ObjectModel($runner);
39720
39721   if (config && config.scenario_output) {
39722     output = config.scenario_output.split(',');
39723   }
39724
39725   angular.forEach(angular.scenario.output, function(fn, name) {
39726     if (!output.length || output.indexOf(name) != -1) {
39727       var context = body.append('<div></div>').find('div:last');
39728       context.attr('id', name);
39729       fn.call({}, context, $runner, objModel);
39730     }
39731   });
39732
39733   if (!/^http/.test(href) && !/^https/.test(href)) {
39734     body.append('<p id="system-error"></p>');
39735     body.find('#system-error').text(
39736       'Scenario runner must be run using http or https. The protocol ' +
39737       href.split(':')[0] + ':// is not supported.'
39738     );
39739     return;
39740   }
39741
39742   var appFrame = body.append('<div id="application"></div>').find('#application');
39743   var application = new angular.scenario.Application(appFrame);
39744
39745   $runner.on('RunnerEnd', function() {
39746     appFrame.css('display', 'none');
39747     appFrame.find('iframe').attr('src', 'about:blank');
39748   });
39749
39750   $runner.on('RunnerError', function(error) {
39751     if (window.console) {
39752       console.log(formatException(error));
39753     } else {
39754       // Do something for IE
39755       alert(error);
39756     }
39757   });
39758
39759   $runner.run(application);
39760 };
39761
39762 /**
39763  * Iterates through list with iterator function that must call the
39764  * continueFunction to continue iterating.
39765  *
39766  * @param {Array} list list to iterate over
39767  * @param {function()} iterator Callback function(value, continueFunction)
39768  * @param {function()} done Callback function(error, result) called when
39769  *   iteration finishes or an error occurs.
39770  */
39771 function asyncForEach(list, iterator, done) {
39772   var i = 0;
39773   function loop(error, index) {
39774     if (index && index > i) {
39775       i = index;
39776     }
39777     if (error || i >= list.length) {
39778       done(error);
39779     } else {
39780       try {
39781         iterator(list[i++], loop);
39782       } catch (e) {
39783         done(e);
39784       }
39785     }
39786   }
39787   loop();
39788 }
39789
39790 /**
39791  * Formats an exception into a string with the stack trace, but limits
39792  * to a specific line length.
39793  *
39794  * @param {Object} error The exception to format, can be anything throwable
39795  * @param {Number=} [maxStackLines=5] max lines of the stack trace to include
39796  *  default is 5.
39797  */
39798 function formatException(error, maxStackLines) {
39799   maxStackLines = maxStackLines || 5;
39800   var message = error.toString();
39801   if (error.stack) {
39802     var stack = error.stack.split('\n');
39803     if (stack[0].indexOf(message) === -1) {
39804       maxStackLines++;
39805       stack.unshift(error.message);
39806     }
39807     message = stack.slice(0, maxStackLines).join('\n');
39808   }
39809   return message;
39810 }
39811
39812 /**
39813  * Returns a function that gets the file name and line number from a
39814  * location in the stack if available based on the call site.
39815  *
39816  * Note: this returns another function because accessing .stack is very
39817  * expensive in Chrome.
39818  *
39819  * @param {Number} offset Number of stack lines to skip
39820  */
39821 function callerFile(offset) {
39822   var error = new Error();
39823
39824   return function() {
39825     var line = (error.stack || '').split('\n')[offset];
39826
39827     // Clean up the stack trace line
39828     if (line) {
39829       if (line.indexOf('@') !== -1) {
39830         // Firefox
39831         line = line.substring(line.indexOf('@') + 1);
39832       } else {
39833         // Chrome
39834         line = line.substring(line.indexOf('(') + 1).replace(')', '');
39835       }
39836     }
39837
39838     return line || '';
39839   };
39840 }
39841
39842
39843 /**
39844  * Don't use the jQuery trigger method since it works incorrectly.
39845  *
39846  * jQuery notifies listeners and then changes the state of a checkbox and
39847  * does not create a real browser event. A real click changes the state of
39848  * the checkbox and then notifies listeners.
39849  *
39850  * To work around this we instead use our own handler that fires a real event.
39851  */
39852 (function(fn) {
39853   // We need a handle to the original trigger function for input tests.
39854   var parentTrigger = fn._originalTrigger = fn.trigger;
39855   fn.trigger = function(type) {
39856     if (/(click|change|keydown|blur|input|mousedown|mouseup)/.test(type)) {
39857       var processDefaults = [];
39858       this.each(function(index, node) {
39859         processDefaults.push(browserTrigger(node, type));
39860       });
39861
39862       // this is not compatible with jQuery - we return an array of returned values,
39863       // so that scenario runner know whether JS code has preventDefault() of the event or not...
39864       return processDefaults;
39865     }
39866     return parentTrigger.apply(this, arguments);
39867   };
39868 })(_jQuery.fn);
39869
39870 /**
39871  * Finds all bindings with the substring match of name and returns an
39872  * array of their values.
39873  *
39874  * @param {string} bindExp The name to match
39875  * @return {Array.<string>} String of binding values
39876  */
39877 _jQuery.fn.bindings = function(windowJquery, bindExp) {
39878   var result = [], match,
39879       bindSelector = '.ng-binding:visible';
39880   if (angular.isString(bindExp)) {
39881     bindExp = bindExp.replace(/\s/g, '');
39882     match = function(actualExp) {
39883       if (actualExp) {
39884         actualExp = actualExp.replace(/\s/g, '');
39885         if (actualExp == bindExp) return true;
39886         if (actualExp.indexOf(bindExp) === 0) {
39887           return actualExp.charAt(bindExp.length) == '|';
39888         }
39889       }
39890     };
39891   } else if (bindExp) {
39892     match = function(actualExp) {
39893       return actualExp && bindExp.exec(actualExp);
39894     };
39895   } else {
39896     match = function(actualExp) {
39897       return !!actualExp;
39898     };
39899   }
39900   var selection = this.find(bindSelector);
39901   if (this.is(bindSelector)) {
39902     selection = selection.add(this);
39903   }
39904
39905   function push(value) {
39906     if (angular.isUndefined(value)) {
39907       value = '';
39908     } else if (typeof value !== 'string') {
39909       value = angular.toJson(value);
39910     }
39911     result.push('' + value);
39912   }
39913
39914   selection.each(function() {
39915     var element = windowJquery(this),
39916         bindings;
39917     if (bindings = element.data('$binding')) {
39918       for (var expressions = [], binding, j=0, jj=bindings.length; j < jj; j++) {
39919         binding = bindings[j];
39920
39921         if (binding.expressions) {
39922           expressions = binding.expressions;
39923         } else {
39924           expressions = [binding];
39925         }
39926         for (var scope, expression, i = 0, ii = expressions.length; i < ii; i++) {
39927           expression = expressions[i];
39928           if (match(expression)) {
39929             scope = scope || element.scope();
39930             push(scope.$eval(expression));
39931           }
39932         }
39933       }
39934     }
39935   });
39936   return result;
39937 };
39938
39939 (function() {
39940   /**
39941    * Triggers a browser event. Attempts to choose the right event if one is
39942    * not specified.
39943    *
39944    * @param {Object} element Either a wrapped jQuery/jqLite node or a DOMElement
39945    * @param {string} eventType Optional event type
39946    * @param {Object=} eventData An optional object which contains additional event data (such as x,y
39947    * coordinates, keys, etc...) that are passed into the event when triggered
39948    */
39949   window.browserTrigger = function browserTrigger(element, eventType, eventData) {
39950     if (element && !element.nodeName) element = element[0];
39951     if (!element) return;
39952
39953     eventData = eventData || {};
39954     var relatedTarget = eventData.relatedTarget || element;
39955     var keys = eventData.keys;
39956     var x = eventData.x;
39957     var y = eventData.y;
39958
39959     var inputType = (element.type) ? element.type.toLowerCase() : null,
39960         nodeName = element.nodeName.toLowerCase();
39961     if (!eventType) {
39962       eventType = {
39963         'text':            'change',
39964         'textarea':        'change',
39965         'hidden':          'change',
39966         'password':        'change',
39967         'button':          'click',
39968         'submit':          'click',
39969         'reset':           'click',
39970         'image':           'click',
39971         'checkbox':        'click',
39972         'radio':           'click',
39973         'select-one':      'change',
39974         'select-multiple': 'change',
39975         '_default_':       'click'
39976       }[inputType || '_default_'];
39977     }
39978
39979     if (nodeName == 'option') {
39980       element.parentNode.value = element.value;
39981       element = element.parentNode;
39982       eventType = 'change';
39983     }
39984
39985     keys = keys || [];
39986     function pressed(key) {
39987       return keys.indexOf(key) !== -1;
39988     }
39989
39990     var evnt;
39991     if (/transitionend/.test(eventType)) {
39992       if (window.WebKitTransitionEvent) {
39993         evnt = new WebKitTransitionEvent(eventType, eventData);
39994         evnt.initEvent(eventType, false, true);
39995       } else {
39996         try {
39997           evnt = new TransitionEvent(eventType, eventData);
39998         }
39999         catch (e) {
40000           evnt = document.createEvent('TransitionEvent');
40001           evnt.initTransitionEvent(eventType, null, null, null, eventData.elapsedTime || 0);
40002         }
40003       }
40004     } else if (/animationend/.test(eventType)) {
40005       if (window.WebKitAnimationEvent) {
40006         evnt = new WebKitAnimationEvent(eventType, eventData);
40007         evnt.initEvent(eventType, false, true);
40008       } else {
40009         try {
40010           evnt = new AnimationEvent(eventType, eventData);
40011         }
40012         catch (e) {
40013           evnt = document.createEvent('AnimationEvent');
40014           evnt.initAnimationEvent(eventType, null, null, null, eventData.elapsedTime || 0);
40015         }
40016       }
40017     } else if (/touch/.test(eventType) && supportsTouchEvents()) {
40018       evnt = createTouchEvent(element, eventType, x, y);
40019     } else {
40020       evnt = document.createEvent('MouseEvents');
40021       x = x || 0;
40022       y = y || 0;
40023       evnt.initMouseEvent(eventType, true, true, window, 0, x, y, x, y, pressed('ctrl'),
40024           pressed('alt'), pressed('shift'), pressed('meta'), 0, relatedTarget);
40025     }
40026
40027     /* we're unable to change the timeStamp value directly so this
40028      * is only here to allow for testing where the timeStamp value is
40029      * read */
40030     evnt.$manualTimeStamp = eventData.timeStamp;
40031
40032     if (!evnt) return;
40033
40034     var originalPreventDefault = evnt.preventDefault,
40035         appWindow = element.ownerDocument.defaultView,
40036         fakeProcessDefault = true,
40037         finalProcessDefault,
40038         angular = appWindow.angular || {};
40039
40040     // igor: temporary fix for https://bugzilla.mozilla.org/show_bug.cgi?id=684208
40041     angular['ff-684208-preventDefault'] = false;
40042     evnt.preventDefault = function() {
40043       fakeProcessDefault = false;
40044       return originalPreventDefault.apply(evnt, arguments);
40045     };
40046
40047     element.dispatchEvent(evnt);
40048     finalProcessDefault = !(angular['ff-684208-preventDefault'] || !fakeProcessDefault);
40049
40050     delete angular['ff-684208-preventDefault'];
40051
40052     return finalProcessDefault;
40053   };
40054
40055   function supportsTouchEvents() {
40056     if ('_cached' in supportsTouchEvents) {
40057       return supportsTouchEvents._cached;
40058     }
40059     if (!document.createTouch || !document.createTouchList) {
40060       supportsTouchEvents._cached = false;
40061       return false;
40062     }
40063     try {
40064       document.createEvent('TouchEvent');
40065     } catch (e) {
40066       supportsTouchEvents._cached = false;
40067       return false;
40068     }
40069     supportsTouchEvents._cached = true;
40070     return true;
40071   }
40072
40073   function createTouchEvent(element, eventType, x, y) {
40074     var evnt = new Event(eventType);
40075     x = x || 0;
40076     y = y || 0;
40077
40078     var touch = document.createTouch(window, element, Date.now(), x, y, x, y);
40079     var touches = document.createTouchList(touch);
40080
40081     evnt.touches = touches;
40082
40083     return evnt;
40084   }
40085 }());
40086
40087 /**
40088  * Represents the application currently being tested and abstracts usage
40089  * of iframes or separate windows.
40090  *
40091  * @param {Object} context jQuery wrapper around HTML context.
40092  */
40093 angular.scenario.Application = function(context) {
40094   this.context = context;
40095   context.append(
40096     '<h2>Current URL: <a href="about:blank">None</a></h2>' +
40097     '<div id="test-frames"></div>'
40098   );
40099 };
40100
40101 /**
40102  * Gets the jQuery collection of frames. Don't use this directly because
40103  * frames may go stale.
40104  *
40105  * @private
40106  * @return {Object} jQuery collection
40107  */
40108 angular.scenario.Application.prototype.getFrame_ = function() {
40109   return this.context.find('#test-frames iframe:last');
40110 };
40111
40112 /**
40113  * Gets the window of the test runner frame. Always favor executeAction()
40114  * instead of this method since it prevents you from getting a stale window.
40115  *
40116  * @private
40117  * @return {Object} the window of the frame
40118  */
40119 angular.scenario.Application.prototype.getWindow_ = function() {
40120   var contentWindow = this.getFrame_().prop('contentWindow');
40121   if (!contentWindow) {
40122     throw 'Frame window is not accessible.';
40123   }
40124   return contentWindow;
40125 };
40126
40127 /**
40128  * Changes the location of the frame.
40129  *
40130  * @param {string} url The URL. If it begins with a # then only the
40131  *   hash of the page is changed.
40132  * @param {function()} loadFn function($window, $document) Called when frame loads.
40133  * @param {function()} errorFn function(error) Called if any error when loading.
40134  */
40135 angular.scenario.Application.prototype.navigateTo = function(url, loadFn, errorFn) {
40136   var self = this;
40137   var frame = self.getFrame_();
40138   //TODO(esprehn): Refactor to use rethrow()
40139   errorFn = errorFn || function(e) { throw e; };
40140   if (url === 'about:blank') {
40141     errorFn('Sandbox Error: Navigating to about:blank is not allowed.');
40142   } else if (url.charAt(0) === '#') {
40143     url = frame.attr('src').split('#')[0] + url;
40144     frame.attr('src', url);
40145     self.executeAction(loadFn);
40146   } else {
40147     frame.remove();
40148     self.context.find('#test-frames').append('<iframe>');
40149     frame = self.getFrame_();
40150
40151     frame.load(function() {
40152       frame.off();
40153       try {
40154         var $window = self.getWindow_();
40155
40156         if (!$window.angular) {
40157           self.executeAction(loadFn);
40158           return;
40159         }
40160
40161         if (!$window.angular.resumeBootstrap) {
40162           $window.angular.resumeDeferredBootstrap = resumeDeferredBootstrap;
40163         } else {
40164           resumeDeferredBootstrap();
40165         }
40166
40167       } catch (e) {
40168         errorFn(e);
40169       }
40170
40171       function resumeDeferredBootstrap() {
40172         // Disable animations
40173         var $injector = $window.angular.resumeBootstrap([['$provide', function($provide) {
40174           return ['$animate', function($animate) {
40175             $animate.enabled(false);
40176           }];
40177         }]]);
40178         self.rootElement = $injector.get('$rootElement')[0];
40179         self.executeAction(loadFn);
40180       }
40181     }).attr('src', url);
40182
40183     // for IE compatibility set the name *after* setting the frame url
40184     frame[0].contentWindow.name = "NG_DEFER_BOOTSTRAP!";
40185   }
40186   self.context.find('> h2 a').attr('href', url).text(url);
40187 };
40188
40189 /**
40190  * Executes a function in the context of the tested application. Will wait
40191  * for all pending angular xhr requests before executing.
40192  *
40193  * @param {function()} action The callback to execute. function($window, $document)
40194  *  $document is a jQuery wrapped document.
40195  */
40196 angular.scenario.Application.prototype.executeAction = function(action) {
40197   var self = this;
40198   var $window = this.getWindow_();
40199   if (!$window.document) {
40200     throw 'Sandbox Error: Application document not accessible.';
40201   }
40202   if (!$window.angular) {
40203     return action.call(this, $window, _jQuery($window.document));
40204   }
40205
40206   if (!!this.rootElement) {
40207     executeWithElement(this.rootElement);
40208   } else {
40209     angularInit($window.document, angular.bind(this, executeWithElement));
40210   }
40211
40212   function executeWithElement(element) {
40213     var $injector = $window.angular.element(element).injector();
40214     var $element = _jQuery(element);
40215
40216     $element.injector = function() {
40217       return $injector;
40218     };
40219
40220     $injector.invoke(function($browser) {
40221       $browser.notifyWhenNoOutstandingRequests(function() {
40222         action.call(self, $window, $element);
40223       });
40224     });
40225   }
40226 };
40227
40228 /**
40229  * The representation of define blocks. Don't used directly, instead use
40230  * define() in your tests.
40231  *
40232  * @param {string} descName Name of the block
40233  * @param {Object} parent describe or undefined if the root.
40234  */
40235 angular.scenario.Describe = function(descName, parent) {
40236   this.only = parent && parent.only;
40237   this.beforeEachFns = [];
40238   this.afterEachFns = [];
40239   this.its = [];
40240   this.children = [];
40241   this.name = descName;
40242   this.parent = parent;
40243   this.id = angular.scenario.Describe.id++;
40244
40245   /**
40246    * Calls all before functions.
40247    */
40248   var beforeEachFns = this.beforeEachFns;
40249   this.setupBefore = function() {
40250     if (parent) parent.setupBefore.call(this);
40251     angular.forEach(beforeEachFns, function(fn) { fn.call(this); }, this);
40252   };
40253
40254   /**
40255    * Calls all after functions.
40256    */
40257   var afterEachFns = this.afterEachFns;
40258   this.setupAfter  = function() {
40259     angular.forEach(afterEachFns, function(fn) { fn.call(this); }, this);
40260     if (parent) parent.setupAfter.call(this);
40261   };
40262 };
40263
40264 // Shared Unique ID generator for every describe block
40265 angular.scenario.Describe.id = 0;
40266
40267 // Shared Unique ID generator for every it (spec)
40268 angular.scenario.Describe.specId = 0;
40269
40270 /**
40271  * Defines a block to execute before each it or nested describe.
40272  *
40273  * @param {function()} body Body of the block.
40274  */
40275 angular.scenario.Describe.prototype.beforeEach = function(body) {
40276   this.beforeEachFns.push(body);
40277 };
40278
40279 /**
40280  * Defines a block to execute after each it or nested describe.
40281  *
40282  * @param {function()} body Body of the block.
40283  */
40284 angular.scenario.Describe.prototype.afterEach = function(body) {
40285   this.afterEachFns.push(body);
40286 };
40287
40288 /**
40289  * Creates a new describe block that's a child of this one.
40290  *
40291  * @param {string} name Name of the block. Appended to the parent block's name.
40292  * @param {function()} body Body of the block.
40293  */
40294 angular.scenario.Describe.prototype.describe = function(name, body) {
40295   var child = new angular.scenario.Describe(name, this);
40296   this.children.push(child);
40297   body.call(child);
40298 };
40299
40300 /**
40301  * Same as describe() but makes ddescribe blocks the only to run.
40302  *
40303  * @param {string} name Name of the test.
40304  * @param {function()} body Body of the block.
40305  */
40306 angular.scenario.Describe.prototype.ddescribe = function(name, body) {
40307   var child = new angular.scenario.Describe(name, this);
40308   child.only = true;
40309   this.children.push(child);
40310   body.call(child);
40311 };
40312
40313 /**
40314  * Use to disable a describe block.
40315  */
40316 angular.scenario.Describe.prototype.xdescribe = angular.noop;
40317
40318 /**
40319  * Defines a test.
40320  *
40321  * @param {string} name Name of the test.
40322  * @param {function()} body Body of the block.
40323  */
40324 angular.scenario.Describe.prototype.it = function(name, body) {
40325   this.its.push({
40326     id: angular.scenario.Describe.specId++,
40327     definition: this,
40328     only: this.only,
40329     name: name,
40330     before: this.setupBefore,
40331     body: body,
40332     after: this.setupAfter
40333   });
40334 };
40335
40336 /**
40337  * Same as it() but makes iit tests the only test to run.
40338  *
40339  * @param {string} name Name of the test.
40340  * @param {function()} body Body of the block.
40341  */
40342 angular.scenario.Describe.prototype.iit = function(name, body) {
40343   this.it.apply(this, arguments);
40344   this.its[this.its.length - 1].only = true;
40345 };
40346
40347 /**
40348  * Use to disable a test block.
40349  */
40350 angular.scenario.Describe.prototype.xit = angular.noop;
40351
40352 /**
40353  * Gets an array of functions representing all the tests (recursively).
40354  * that can be executed with SpecRunner's.
40355  *
40356  * @return {Array<Object>} Array of it blocks {
40357  *   definition : Object // parent Describe
40358  *   only: boolean
40359  *   name: string
40360  *   before: Function
40361  *   body: Function
40362  *   after: Function
40363  *  }
40364  */
40365 angular.scenario.Describe.prototype.getSpecs = function() {
40366   var specs = arguments[0] || [];
40367   angular.forEach(this.children, function(child) {
40368     child.getSpecs(specs);
40369   });
40370   angular.forEach(this.its, function(it) {
40371     specs.push(it);
40372   });
40373   var only = [];
40374   angular.forEach(specs, function(it) {
40375     if (it.only) {
40376       only.push(it);
40377     }
40378   });
40379   return (only.length && only) || specs;
40380 };
40381
40382 /**
40383  * A future action in a spec.
40384  *
40385  * @param {string} name name of the future action
40386  * @param {function()} behavior future callback(error, result)
40387  * @param {function()} line Optional. function that returns the file/line number.
40388  */
40389 angular.scenario.Future = function(name, behavior, line) {
40390   this.name = name;
40391   this.behavior = behavior;
40392   this.fulfilled = false;
40393   this.value = undefined;
40394   this.parser = angular.identity;
40395   this.line = line || function() { return ''; };
40396 };
40397
40398 /**
40399  * Executes the behavior of the closure.
40400  *
40401  * @param {function()} doneFn Callback function(error, result)
40402  */
40403 angular.scenario.Future.prototype.execute = function(doneFn) {
40404   var self = this;
40405   this.behavior(function(error, result) {
40406     self.fulfilled = true;
40407     if (result) {
40408       try {
40409         result = self.parser(result);
40410       } catch (e) {
40411         error = e;
40412       }
40413     }
40414     self.value = error || result;
40415     doneFn(error, result);
40416   });
40417 };
40418
40419 /**
40420  * Configures the future to convert its final with a function fn(value)
40421  *
40422  * @param {function()} fn function(value) that returns the parsed value
40423  */
40424 angular.scenario.Future.prototype.parsedWith = function(fn) {
40425   this.parser = fn;
40426   return this;
40427 };
40428
40429 /**
40430  * Configures the future to parse its final value from JSON
40431  * into objects.
40432  */
40433 angular.scenario.Future.prototype.fromJson = function() {
40434   return this.parsedWith(angular.fromJson);
40435 };
40436
40437 /**
40438  * Configures the future to convert its final value from objects
40439  * into JSON.
40440  */
40441 angular.scenario.Future.prototype.toJson = function() {
40442   return this.parsedWith(angular.toJson);
40443 };
40444
40445 /**
40446  * Maintains an object tree from the runner events.
40447  *
40448  * @param {Object} runner The scenario Runner instance to connect to.
40449  *
40450  * TODO(esprehn): Every output type creates one of these, but we probably
40451  *  want one global shared instance. Need to handle events better too
40452  *  so the HTML output doesn't need to do spec model.getSpec(spec.id)
40453  *  silliness.
40454  *
40455  * TODO(vojta) refactor on, emit methods (from all objects) - use inheritance
40456  */
40457 angular.scenario.ObjectModel = function(runner) {
40458   var self = this;
40459
40460   this.specMap = {};
40461   this.listeners = [];
40462   this.value = {
40463     name: '',
40464     children: {}
40465   };
40466
40467   runner.on('SpecBegin', function(spec) {
40468     var block = self.value,
40469         definitions = [];
40470
40471     angular.forEach(self.getDefinitionPath(spec), function(def) {
40472       if (!block.children[def.name]) {
40473         block.children[def.name] = {
40474           id: def.id,
40475           name: def.name,
40476           children: {},
40477           specs: {}
40478         };
40479       }
40480       block = block.children[def.name];
40481       definitions.push(def.name);
40482     });
40483
40484     var it = self.specMap[spec.id] =
40485              block.specs[spec.name] =
40486              new angular.scenario.ObjectModel.Spec(spec.id, spec.name, definitions);
40487
40488     // forward the event
40489     self.emit('SpecBegin', it);
40490   });
40491
40492   runner.on('SpecError', function(spec, error) {
40493     var it = self.getSpec(spec.id);
40494     it.status = 'error';
40495     it.error = error;
40496
40497     // forward the event
40498     self.emit('SpecError', it, error);
40499   });
40500
40501   runner.on('SpecEnd', function(spec) {
40502     var it = self.getSpec(spec.id);
40503     complete(it);
40504
40505     // forward the event
40506     self.emit('SpecEnd', it);
40507   });
40508
40509   runner.on('StepBegin', function(spec, step) {
40510     var it = self.getSpec(spec.id);
40511     step = new angular.scenario.ObjectModel.Step(step.name);
40512     it.steps.push(step);
40513
40514     // forward the event
40515     self.emit('StepBegin', it, step);
40516   });
40517
40518   runner.on('StepEnd', function(spec) {
40519     var it = self.getSpec(spec.id);
40520     var step = it.getLastStep();
40521     if (step.name !== step.name) {
40522       throw 'Events fired in the wrong order. Step names don\'t match.';
40523     }
40524     complete(step);
40525
40526     // forward the event
40527     self.emit('StepEnd', it, step);
40528   });
40529
40530   runner.on('StepFailure', function(spec, step, error) {
40531     var it = self.getSpec(spec.id),
40532         modelStep = it.getLastStep();
40533
40534     modelStep.setErrorStatus('failure', error, step.line());
40535     it.setStatusFromStep(modelStep);
40536
40537     // forward the event
40538     self.emit('StepFailure', it, modelStep, error);
40539   });
40540
40541   runner.on('StepError', function(spec, step, error) {
40542     var it = self.getSpec(spec.id),
40543         modelStep = it.getLastStep();
40544
40545     modelStep.setErrorStatus('error', error, step.line());
40546     it.setStatusFromStep(modelStep);
40547
40548     // forward the event
40549     self.emit('StepError', it, modelStep, error);
40550   });
40551
40552   runner.on('RunnerBegin', function() {
40553     self.emit('RunnerBegin');
40554   });
40555   runner.on('RunnerEnd', function() {
40556     self.emit('RunnerEnd');
40557   });
40558
40559   function complete(item) {
40560     item.endTime = Date.now();
40561     item.duration = item.endTime - item.startTime;
40562     item.status = item.status || 'success';
40563   }
40564 };
40565
40566 /**
40567  * Adds a listener for an event.
40568  *
40569  * @param {string} eventName Name of the event to add a handler for
40570  * @param {function()} listener Function that will be called when event is fired
40571  */
40572 angular.scenario.ObjectModel.prototype.on = function(eventName, listener) {
40573   eventName = eventName.toLowerCase();
40574   this.listeners[eventName] = this.listeners[eventName] || [];
40575   this.listeners[eventName].push(listener);
40576 };
40577
40578 /**
40579  * Emits an event which notifies listeners and passes extra
40580  * arguments.
40581  *
40582  * @param {string} eventName Name of the event to fire.
40583  */
40584 angular.scenario.ObjectModel.prototype.emit = function(eventName) {
40585   var self = this,
40586       args = Array.prototype.slice.call(arguments, 1);
40587
40588   eventName = eventName.toLowerCase();
40589
40590   if (this.listeners[eventName]) {
40591     angular.forEach(this.listeners[eventName], function(listener) {
40592       listener.apply(self, args);
40593     });
40594   }
40595 };
40596
40597 /**
40598  * Computes the path of definition describe blocks that wrap around
40599  * this spec.
40600  *
40601  * @param spec Spec to compute the path for.
40602  * @return {Array<Describe>} The describe block path
40603  */
40604 angular.scenario.ObjectModel.prototype.getDefinitionPath = function(spec) {
40605   var path = [];
40606   var currentDefinition = spec.definition;
40607   while (currentDefinition && currentDefinition.name) {
40608     path.unshift(currentDefinition);
40609     currentDefinition = currentDefinition.parent;
40610   }
40611   return path;
40612 };
40613
40614 /**
40615  * Gets a spec by id.
40616  *
40617  * @param {string} id The id of the spec to get the object for.
40618  * @return {Object} the Spec instance
40619  */
40620 angular.scenario.ObjectModel.prototype.getSpec = function(id) {
40621   return this.specMap[id];
40622 };
40623
40624 /**
40625  * A single it block.
40626  *
40627  * @param {string} id Id of the spec
40628  * @param {string} name Name of the spec
40629  * @param {Array<string>=} definitionNames List of all describe block names that wrap this spec
40630  */
40631 angular.scenario.ObjectModel.Spec = function(id, name, definitionNames) {
40632   this.id = id;
40633   this.name = name;
40634   this.startTime = Date.now();
40635   this.steps = [];
40636   this.fullDefinitionName = (definitionNames || []).join(' ');
40637 };
40638
40639 /**
40640  * Adds a new step to the Spec.
40641  *
40642  * @param {string} name Name of the step (really name of the future)
40643  * @return {Object} the added step
40644  */
40645 angular.scenario.ObjectModel.Spec.prototype.addStep = function(name) {
40646   var step = new angular.scenario.ObjectModel.Step(name);
40647   this.steps.push(step);
40648   return step;
40649 };
40650
40651 /**
40652  * Gets the most recent step.
40653  *
40654  * @return {Object} the step
40655  */
40656 angular.scenario.ObjectModel.Spec.prototype.getLastStep = function() {
40657   return this.steps[this.steps.length - 1];
40658 };
40659
40660 /**
40661  * Set status of the Spec from given Step
40662  *
40663  * @param {angular.scenario.ObjectModel.Step} step
40664  */
40665 angular.scenario.ObjectModel.Spec.prototype.setStatusFromStep = function(step) {
40666   if (!this.status || step.status == 'error') {
40667     this.status = step.status;
40668     this.error = step.error;
40669     this.line = step.line;
40670   }
40671 };
40672
40673 /**
40674  * A single step inside a Spec.
40675  *
40676  * @param {string} name Name of the step
40677  */
40678 angular.scenario.ObjectModel.Step = function(name) {
40679   this.name = name;
40680   this.startTime = Date.now();
40681 };
40682
40683 /**
40684  * Helper method for setting all error status related properties
40685  *
40686  * @param {string} status
40687  * @param {string} error
40688  * @param {string} line
40689  */
40690 angular.scenario.ObjectModel.Step.prototype.setErrorStatus = function(status, error, line) {
40691   this.status = status;
40692   this.error = error;
40693   this.line = line;
40694 };
40695
40696 /**
40697  * Runner for scenarios
40698  *
40699  * Has to be initialized before any test is loaded,
40700  * because it publishes the API into window (global space).
40701  */
40702 angular.scenario.Runner = function($window) {
40703   this.listeners = [];
40704   this.$window = $window;
40705   this.rootDescribe = new angular.scenario.Describe();
40706   this.currentDescribe = this.rootDescribe;
40707   this.api = {
40708     it: this.it,
40709     iit: this.iit,
40710     xit: angular.noop,
40711     describe: this.describe,
40712     ddescribe: this.ddescribe,
40713     xdescribe: angular.noop,
40714     beforeEach: this.beforeEach,
40715     afterEach: this.afterEach
40716   };
40717   angular.forEach(this.api, angular.bind(this, function(fn, key) {
40718     this.$window[key] = angular.bind(this, fn);
40719   }));
40720 };
40721
40722 /**
40723  * Emits an event which notifies listeners and passes extra
40724  * arguments.
40725  *
40726  * @param {string} eventName Name of the event to fire.
40727  */
40728 angular.scenario.Runner.prototype.emit = function(eventName) {
40729   var self = this;
40730   var args = Array.prototype.slice.call(arguments, 1);
40731   eventName = eventName.toLowerCase();
40732   if (!this.listeners[eventName]) {
40733     return;
40734   }
40735   angular.forEach(this.listeners[eventName], function(listener) {
40736     listener.apply(self, args);
40737   });
40738 };
40739
40740 /**
40741  * Adds a listener for an event.
40742  *
40743  * @param {string} eventName The name of the event to add a handler for
40744  * @param {string} listener The fn(...) that takes the extra arguments from emit()
40745  */
40746 angular.scenario.Runner.prototype.on = function(eventName, listener) {
40747   eventName = eventName.toLowerCase();
40748   this.listeners[eventName] = this.listeners[eventName] || [];
40749   this.listeners[eventName].push(listener);
40750 };
40751
40752 /**
40753  * Defines a describe block of a spec.
40754  *
40755  * @see Describe.js
40756  *
40757  * @param {string} name Name of the block
40758  * @param {function()} body Body of the block
40759  */
40760 angular.scenario.Runner.prototype.describe = function(name, body) {
40761   var self = this;
40762   this.currentDescribe.describe(name, function() {
40763     var parentDescribe = self.currentDescribe;
40764     self.currentDescribe = this;
40765     try {
40766       body.call(this);
40767     } finally {
40768       self.currentDescribe = parentDescribe;
40769     }
40770   });
40771 };
40772
40773 /**
40774  * Same as describe, but makes ddescribe the only blocks to run.
40775  *
40776  * @see Describe.js
40777  *
40778  * @param {string} name Name of the block
40779  * @param {function()} body Body of the block
40780  */
40781 angular.scenario.Runner.prototype.ddescribe = function(name, body) {
40782   var self = this;
40783   this.currentDescribe.ddescribe(name, function() {
40784     var parentDescribe = self.currentDescribe;
40785     self.currentDescribe = this;
40786     try {
40787       body.call(this);
40788     } finally {
40789       self.currentDescribe = parentDescribe;
40790     }
40791   });
40792 };
40793
40794 /**
40795  * Defines a test in a describe block of a spec.
40796  *
40797  * @see Describe.js
40798  *
40799  * @param {string} name Name of the block
40800  * @param {function()} body Body of the block
40801  */
40802 angular.scenario.Runner.prototype.it = function(name, body) {
40803   this.currentDescribe.it(name, body);
40804 };
40805
40806 /**
40807  * Same as it, but makes iit tests the only tests to run.
40808  *
40809  * @see Describe.js
40810  *
40811  * @param {string} name Name of the block
40812  * @param {function()} body Body of the block
40813  */
40814 angular.scenario.Runner.prototype.iit = function(name, body) {
40815   this.currentDescribe.iit(name, body);
40816 };
40817
40818 /**
40819  * Defines a function to be called before each it block in the describe
40820  * (and before all nested describes).
40821  *
40822  * @see Describe.js
40823  *
40824  * @param {function()} Callback to execute
40825  */
40826 angular.scenario.Runner.prototype.beforeEach = function(body) {
40827   this.currentDescribe.beforeEach(body);
40828 };
40829
40830 /**
40831  * Defines a function to be called after each it block in the describe
40832  * (and before all nested describes).
40833  *
40834  * @see Describe.js
40835  *
40836  * @param {function()} Callback to execute
40837  */
40838 angular.scenario.Runner.prototype.afterEach = function(body) {
40839   this.currentDescribe.afterEach(body);
40840 };
40841
40842 /**
40843  * Creates a new spec runner.
40844  *
40845  * @private
40846  * @param {Object} scope parent scope
40847  */
40848 angular.scenario.Runner.prototype.createSpecRunner_ = function(scope) {
40849   var child = scope.$new();
40850   var Cls = angular.scenario.SpecRunner;
40851
40852   // Export all the methods to child scope manually as now we don't mess controllers with scopes
40853   // TODO(vojta): refactor scenario runner so that these objects are not tightly coupled as current
40854   for (var name in Cls.prototype) {
40855     child[name] = angular.bind(child, Cls.prototype[name]);
40856   }
40857
40858   Cls.call(child);
40859   return child;
40860 };
40861
40862 /**
40863  * Runs all the loaded tests with the specified runner class on the
40864  * provided application.
40865  *
40866  * @param {angular.scenario.Application} application App to remote control.
40867  */
40868 angular.scenario.Runner.prototype.run = function(application) {
40869   var self = this;
40870   var $root = angular.injector(['ng']).get('$rootScope');
40871   angular.extend($root, this);
40872   angular.forEach(angular.scenario.Runner.prototype, function(fn, name) {
40873     $root[name] = angular.bind(self, fn);
40874   });
40875   $root.application = application;
40876   $root.emit('RunnerBegin');
40877   asyncForEach(this.rootDescribe.getSpecs(), function(spec, specDone) {
40878     var dslCache = {};
40879     var runner = self.createSpecRunner_($root);
40880     angular.forEach(angular.scenario.dsl, function(fn, key) {
40881       dslCache[key] = fn.call($root);
40882     });
40883     angular.forEach(angular.scenario.dsl, function(fn, key) {
40884       self.$window[key] = function() {
40885         var line = callerFile(3);
40886         var scope = runner.$new();
40887
40888         // Make the dsl accessible on the current chain
40889         scope.dsl = {};
40890         angular.forEach(dslCache, function(fn, key) {
40891           scope.dsl[key] = function() {
40892             return dslCache[key].apply(scope, arguments);
40893           };
40894         });
40895
40896         // Make these methods work on the current chain
40897         scope.addFuture = function() {
40898           Array.prototype.push.call(arguments, line);
40899           return angular.scenario.SpecRunner.
40900             prototype.addFuture.apply(scope, arguments);
40901         };
40902         scope.addFutureAction = function() {
40903           Array.prototype.push.call(arguments, line);
40904           return angular.scenario.SpecRunner.
40905             prototype.addFutureAction.apply(scope, arguments);
40906         };
40907
40908         return scope.dsl[key].apply(scope, arguments);
40909       };
40910     });
40911     runner.run(spec, function() {
40912       runner.$destroy();
40913       specDone.apply(this, arguments);
40914     });
40915   },
40916   function(error) {
40917     if (error) {
40918       self.emit('RunnerError', error);
40919     }
40920     self.emit('RunnerEnd');
40921   });
40922 };
40923
40924 /**
40925  * This class is the "this" of the it/beforeEach/afterEach method.
40926  * Responsibilities:
40927  *   - "this" for it/beforeEach/afterEach
40928  *   - keep state for single it/beforeEach/afterEach execution
40929  *   - keep track of all of the futures to execute
40930  *   - run single spec (execute each future)
40931  */
40932 angular.scenario.SpecRunner = function() {
40933   this.futures = [];
40934   this.afterIndex = 0;
40935 };
40936
40937 /**
40938  * Executes a spec which is an it block with associated before/after functions
40939  * based on the describe nesting.
40940  *
40941  * @param {Object} spec A spec object
40942  * @param {function()} specDone function that is called when the spec finishes,
40943  *                              of the form `Function(error, index)`
40944  */
40945 angular.scenario.SpecRunner.prototype.run = function(spec, specDone) {
40946   var self = this;
40947   this.spec = spec;
40948
40949   this.emit('SpecBegin', spec);
40950
40951   try {
40952     spec.before.call(this);
40953     spec.body.call(this);
40954     this.afterIndex = this.futures.length;
40955     spec.after.call(this);
40956   } catch (e) {
40957     this.emit('SpecError', spec, e);
40958     this.emit('SpecEnd', spec);
40959     specDone();
40960     return;
40961   }
40962
40963   var handleError = function(error, done) {
40964     if (self.error) {
40965       return done();
40966     }
40967     self.error = true;
40968     done(null, self.afterIndex);
40969   };
40970
40971   asyncForEach(
40972     this.futures,
40973     function(future, futureDone) {
40974       self.step = future;
40975       self.emit('StepBegin', spec, future);
40976       try {
40977         future.execute(function(error) {
40978           if (error) {
40979             self.emit('StepFailure', spec, future, error);
40980             self.emit('StepEnd', spec, future);
40981             return handleError(error, futureDone);
40982           }
40983           self.emit('StepEnd', spec, future);
40984           self.$window.setTimeout(function() { futureDone(); }, 0);
40985         });
40986       } catch (e) {
40987         self.emit('StepError', spec, future, e);
40988         self.emit('StepEnd', spec, future);
40989         handleError(e, futureDone);
40990       }
40991     },
40992     function(e) {
40993       if (e) {
40994         self.emit('SpecError', spec, e);
40995       }
40996       self.emit('SpecEnd', spec);
40997       // Call done in a timeout so exceptions don't recursively
40998       // call this function
40999       self.$window.setTimeout(function() { specDone(); }, 0);
41000     }
41001   );
41002 };
41003
41004 /**
41005  * Adds a new future action.
41006  *
41007  * Note: Do not pass line manually. It happens automatically.
41008  *
41009  * @param {string} name Name of the future
41010  * @param {function()} behavior Behavior of the future
41011  * @param {function()} line fn() that returns file/line number
41012  */
41013 angular.scenario.SpecRunner.prototype.addFuture = function(name, behavior, line) {
41014   var future = new angular.scenario.Future(name, angular.bind(this, behavior), line);
41015   this.futures.push(future);
41016   return future;
41017 };
41018
41019 /**
41020  * Adds a new future action to be executed on the application window.
41021  *
41022  * Note: Do not pass line manually. It happens automatically.
41023  *
41024  * @param {string} name Name of the future
41025  * @param {function()} behavior Behavior of the future
41026  * @param {function()} line fn() that returns file/line number
41027  */
41028 angular.scenario.SpecRunner.prototype.addFutureAction = function(name, behavior, line) {
41029   var self = this;
41030   var NG = /\[ng\\\:/;
41031   return this.addFuture(name, function(done) {
41032     this.application.executeAction(function($window, $document) {
41033
41034       //TODO(esprehn): Refactor this so it doesn't need to be in here.
41035       $document.elements = function(selector) {
41036         var args = Array.prototype.slice.call(arguments, 1);
41037         selector = (self.selector || '') + ' ' + (selector || '');
41038         selector = _jQuery.trim(selector) || '*';
41039         angular.forEach(args, function(value, index) {
41040           selector = selector.replace('$' + (index + 1), value);
41041         });
41042         var result = $document.find(selector);
41043         if (selector.match(NG)) {
41044           angular.forEach(['[ng-','[data-ng-','[x-ng-'], function(value, index) {
41045             result = result.add(selector.replace(NG, value), $document);
41046           });
41047         }
41048         if (!result.length) {
41049           throw {
41050             type: 'selector',
41051             message: 'Selector ' + selector + ' did not match any elements.'
41052           };
41053         }
41054
41055         return result;
41056       };
41057
41058       try {
41059         behavior.call(self, $window, $document, done);
41060       } catch (e) {
41061         if (e.type && e.type === 'selector') {
41062           done(e.message);
41063         } else {
41064           throw e;
41065         }
41066       }
41067     });
41068   }, line);
41069 };
41070
41071 /**
41072  * Shared DSL statements that are useful to all scenarios.
41073  */
41074
41075  /**
41076  * Usage:
41077  *    pause() pauses until you call resume() in the console
41078  */
41079 angular.scenario.dsl('pause', function() {
41080   return function() {
41081     return this.addFuture('pausing for you to resume', function(done) {
41082       this.emit('InteractivePause', this.spec, this.step);
41083       this.$window.resume = function() { done(); };
41084     });
41085   };
41086 });
41087
41088 /**
41089  * Usage:
41090  *    sleep(seconds) pauses the test for specified number of seconds
41091  */
41092 angular.scenario.dsl('sleep', function() {
41093   return function(time) {
41094     return this.addFuture('sleep for ' + time + ' seconds', function(done) {
41095       this.$window.setTimeout(function() { done(null, time * 1000); }, time * 1000);
41096     });
41097   };
41098 });
41099
41100 /**
41101  * Usage:
41102  *    browser().navigateTo(url) Loads the url into the frame
41103  *    browser().navigateTo(url, fn) where fn(url) is called and returns the URL to navigate to
41104  *    browser().reload() refresh the page (reload the same URL)
41105  *    browser().window.href() window.location.href
41106  *    browser().window.path() window.location.pathname
41107  *    browser().window.search() window.location.search
41108  *    browser().window.hash() window.location.hash without # prefix
41109  *    browser().location().url() see ng.$location#url
41110  *    browser().location().path() see ng.$location#path
41111  *    browser().location().search() see ng.$location#search
41112  *    browser().location().hash() see ng.$location#hash
41113  */
41114 angular.scenario.dsl('browser', function() {
41115   var chain = {};
41116
41117   chain.navigateTo = function(url, delegate) {
41118     var application = this.application;
41119     return this.addFuture("browser navigate to '" + url + "'", function(done) {
41120       if (delegate) {
41121         url = delegate.call(this, url);
41122       }
41123       application.navigateTo(url, function() {
41124         done(null, url);
41125       }, done);
41126     });
41127   };
41128
41129   chain.reload = function() {
41130     var application = this.application;
41131     return this.addFutureAction('browser reload', function($window, $document, done) {
41132       var href = $window.location.href;
41133       application.navigateTo(href, function() {
41134         done(null, href);
41135       }, done);
41136     });
41137   };
41138
41139   chain.window = function() {
41140     var api = {};
41141
41142     api.href = function() {
41143       return this.addFutureAction('window.location.href', function($window, $document, done) {
41144         done(null, $window.location.href);
41145       });
41146     };
41147
41148     api.path = function() {
41149       return this.addFutureAction('window.location.path', function($window, $document, done) {
41150         done(null, $window.location.pathname);
41151       });
41152     };
41153
41154     api.search = function() {
41155       return this.addFutureAction('window.location.search', function($window, $document, done) {
41156         done(null, $window.location.search);
41157       });
41158     };
41159
41160     api.hash = function() {
41161       return this.addFutureAction('window.location.hash', function($window, $document, done) {
41162         done(null, $window.location.hash.replace('#', ''));
41163       });
41164     };
41165
41166     return api;
41167   };
41168
41169   chain.location = function() {
41170     var api = {};
41171
41172     api.url = function() {
41173       return this.addFutureAction('$location.url()', function($window, $document, done) {
41174         done(null, $document.injector().get('$location').url());
41175       });
41176     };
41177
41178     api.path = function() {
41179       return this.addFutureAction('$location.path()', function($window, $document, done) {
41180         done(null, $document.injector().get('$location').path());
41181       });
41182     };
41183
41184     api.search = function() {
41185       return this.addFutureAction('$location.search()', function($window, $document, done) {
41186         done(null, $document.injector().get('$location').search());
41187       });
41188     };
41189
41190     api.hash = function() {
41191       return this.addFutureAction('$location.hash()', function($window, $document, done) {
41192         done(null, $document.injector().get('$location').hash());
41193       });
41194     };
41195
41196     return api;
41197   };
41198
41199   return function() {
41200     return chain;
41201   };
41202 });
41203
41204 /**
41205  * Usage:
41206  *    expect(future).{matcher} where matcher is one of the matchers defined
41207  *    with angular.scenario.matcher
41208  *
41209  * ex. expect(binding("name")).toEqual("Elliott")
41210  */
41211 angular.scenario.dsl('expect', function() {
41212   var chain = angular.extend({}, angular.scenario.matcher);
41213
41214   chain.not = function() {
41215     this.inverse = true;
41216     return chain;
41217   };
41218
41219   return function(future) {
41220     this.future = future;
41221     return chain;
41222   };
41223 });
41224
41225 /**
41226  * Usage:
41227  *    using(selector, label) scopes the next DSL element selection
41228  *
41229  * ex.
41230  *   using('#foo', "'Foo' text field").input('bar')
41231  */
41232 angular.scenario.dsl('using', function() {
41233   return function(selector, label) {
41234     this.selector = _jQuery.trim((this.selector || '') + ' ' + selector);
41235     if (angular.isString(label) && label.length) {
41236       this.label = label + ' ( ' + this.selector + ' )';
41237     } else {
41238       this.label = this.selector;
41239     }
41240     return this.dsl;
41241   };
41242 });
41243
41244 /**
41245  * Usage:
41246  *    binding(name) returns the value of the first matching binding
41247  */
41248 angular.scenario.dsl('binding', function() {
41249   return function(name) {
41250     return this.addFutureAction("select binding '" + name + "'",
41251       function($window, $document, done) {
41252         var values = $document.elements().bindings($window.angular.element, name);
41253         if (!values.length) {
41254           return done("Binding selector '" + name + "' did not match.");
41255         }
41256         done(null, values[0]);
41257     });
41258   };
41259 });
41260
41261 /**
41262  * Usage:
41263  *    input(name).enter(value) enters value in input with specified name
41264  *    input(name).check() checks checkbox
41265  *    input(name).select(value) selects the radio button with specified name/value
41266  *    input(name).val() returns the value of the input.
41267  */
41268 angular.scenario.dsl('input', function() {
41269   var chain = {};
41270   var supportInputEvent = 'oninput' in document.createElement('div') && !(msie && msie <= 11);
41271
41272   chain.enter = function(value, event) {
41273     return this.addFutureAction("input '" + this.name + "' enter '" + value + "'",
41274       function($window, $document, done) {
41275         var input = $document.elements('[ng\\:model="$1"]', this.name).filter(':input');
41276         input.val(value);
41277         input.trigger(event || (supportInputEvent ? 'input' : 'change'));
41278         done();
41279     });
41280   };
41281
41282   chain.check = function() {
41283     return this.addFutureAction("checkbox '" + this.name + "' toggle",
41284       function($window, $document, done) {
41285         var input = $document.elements('[ng\\:model="$1"]', this.name).filter(':checkbox');
41286         input.trigger('click');
41287         done();
41288     });
41289   };
41290
41291   chain.select = function(value) {
41292     return this.addFutureAction("radio button '" + this.name + "' toggle '" + value + "'",
41293       function($window, $document, done) {
41294         var input = $document.
41295           elements('[ng\\:model="$1"][value="$2"]', this.name, value).filter(':radio');
41296         input.trigger('click');
41297         done();
41298     });
41299   };
41300
41301   chain.val = function() {
41302     return this.addFutureAction("return input val", function($window, $document, done) {
41303       var input = $document.elements('[ng\\:model="$1"]', this.name).filter(':input');
41304       done(null,input.val());
41305     });
41306   };
41307
41308   return function(name) {
41309     this.name = name;
41310     return chain;
41311   };
41312 });
41313
41314
41315 /**
41316  * Usage:
41317  *    repeater('#products table', 'Product List').count() number of rows
41318  *    repeater('#products table', 'Product List').row(1) all bindings in row as an array
41319  *    repeater('#products table', 'Product List').column('product.name') all values across all rows
41320  *    in an array
41321  */
41322 angular.scenario.dsl('repeater', function() {
41323   var chain = {};
41324
41325   chain.count = function() {
41326     return this.addFutureAction("repeater '" + this.label + "' count",
41327       function($window, $document, done) {
41328         try {
41329           done(null, $document.elements().length);
41330         } catch (e) {
41331           done(null, 0);
41332         }
41333     });
41334   };
41335
41336   chain.column = function(binding) {
41337     return this.addFutureAction("repeater '" + this.label + "' column '" + binding + "'",
41338       function($window, $document, done) {
41339         done(null, $document.elements().bindings($window.angular.element, binding));
41340     });
41341   };
41342
41343   chain.row = function(index) {
41344     return this.addFutureAction("repeater '" + this.label + "' row '" + index + "'",
41345       function($window, $document, done) {
41346         var matches = $document.elements().slice(index, index + 1);
41347         if (!matches.length) {
41348           return done('row ' + index + ' out of bounds');
41349         }
41350         done(null, matches.bindings($window.angular.element));
41351     });
41352   };
41353
41354   return function(selector, label) {
41355     this.dsl.using(selector, label);
41356     return chain;
41357   };
41358 });
41359
41360 /**
41361  * Usage:
41362  *    select(name).option('value') select one option
41363  *    select(name).options('value1', 'value2', ...) select options from a multi select
41364  */
41365 angular.scenario.dsl('select', function() {
41366   var chain = {};
41367
41368   chain.option = function(value) {
41369     return this.addFutureAction("select '" + this.name + "' option '" + value + "'",
41370       function($window, $document, done) {
41371         var select = $document.elements('select[ng\\:model="$1"]', this.name);
41372         var option = select.find('option[value="' + value + '"]');
41373         if (option.length) {
41374           select.val(value);
41375         } else {
41376           option = select.find('option').filter(function() {
41377             return _jQuery(this).text() === value;
41378           });
41379           if (!option.length) {
41380             option = select.find('option:contains("' + value + '")');
41381           }
41382           if (option.length) {
41383             select.val(option.val());
41384           } else {
41385               return done("option '" + value + "' not found");
41386           }
41387         }
41388         select.trigger('change');
41389         done();
41390     });
41391   };
41392
41393   chain.options = function() {
41394     var values = arguments;
41395     return this.addFutureAction("select '" + this.name + "' options '" + values + "'",
41396       function($window, $document, done) {
41397         var select = $document.elements('select[multiple][ng\\:model="$1"]', this.name);
41398         select.val(values);
41399         select.trigger('change');
41400         done();
41401     });
41402   };
41403
41404   return function(name) {
41405     this.name = name;
41406     return chain;
41407   };
41408 });
41409
41410 /**
41411  * Usage:
41412  *    element(selector, label).count() get the number of elements that match selector
41413  *    element(selector, label).click() clicks an element
41414  *    element(selector, label).mouseover() mouseover an element
41415  *    element(selector, label).mousedown() mousedown an element
41416  *    element(selector, label).mouseup() mouseup an element
41417  *    element(selector, label).query(fn) executes fn(selectedElements, done)
41418  *    element(selector, label).{method}() gets the value (as defined by jQuery, ex. val)
41419  *    element(selector, label).{method}(value) sets the value (as defined by jQuery, ex. val)
41420  *    element(selector, label).{method}(key) gets the value (as defined by jQuery, ex. attr)
41421  *    element(selector, label).{method}(key, value) sets the value (as defined by jQuery, ex. attr)
41422  */
41423 angular.scenario.dsl('element', function() {
41424   var KEY_VALUE_METHODS = ['attr', 'css', 'prop'];
41425   var VALUE_METHODS = [
41426     'val', 'text', 'html', 'height', 'innerHeight', 'outerHeight', 'width',
41427     'innerWidth', 'outerWidth', 'position', 'scrollLeft', 'scrollTop', 'offset'
41428   ];
41429   var chain = {};
41430
41431   chain.count = function() {
41432     return this.addFutureAction("element '" + this.label + "' count",
41433       function($window, $document, done) {
41434         try {
41435           done(null, $document.elements().length);
41436         } catch (e) {
41437           done(null, 0);
41438         }
41439     });
41440   };
41441
41442   chain.click = function() {
41443     return this.addFutureAction("element '" + this.label + "' click",
41444       function($window, $document, done) {
41445         var elements = $document.elements();
41446         var href = elements.attr('href');
41447         var eventProcessDefault = elements.trigger('click')[0];
41448
41449         if (href && elements[0].nodeName.toLowerCase() === 'a' && eventProcessDefault) {
41450           this.application.navigateTo(href, function() {
41451             done();
41452           }, done);
41453         } else {
41454           done();
41455         }
41456     });
41457   };
41458
41459   chain.dblclick = function() {
41460     return this.addFutureAction("element '" + this.label + "' dblclick",
41461       function($window, $document, done) {
41462         var elements = $document.elements();
41463         var href = elements.attr('href');
41464         var eventProcessDefault = elements.trigger('dblclick')[0];
41465
41466         if (href && elements[0].nodeName.toLowerCase() === 'a' && eventProcessDefault) {
41467           this.application.navigateTo(href, function() {
41468             done();
41469           }, done);
41470         } else {
41471           done();
41472         }
41473     });
41474   };
41475
41476   chain.mouseover = function() {
41477     return this.addFutureAction("element '" + this.label + "' mouseover",
41478       function($window, $document, done) {
41479         var elements = $document.elements();
41480         elements.trigger('mouseover');
41481         done();
41482     });
41483   };
41484
41485   chain.mousedown = function() {
41486       return this.addFutureAction("element '" + this.label + "' mousedown",
41487         function($window, $document, done) {
41488           var elements = $document.elements();
41489           elements.trigger('mousedown');
41490           done();
41491       });
41492     };
41493
41494   chain.mouseup = function() {
41495       return this.addFutureAction("element '" + this.label + "' mouseup",
41496         function($window, $document, done) {
41497           var elements = $document.elements();
41498           elements.trigger('mouseup');
41499           done();
41500       });
41501     };
41502
41503   chain.query = function(fn) {
41504     return this.addFutureAction('element ' + this.label + ' custom query',
41505       function($window, $document, done) {
41506         fn.call(this, $document.elements(), done);
41507     });
41508   };
41509
41510   angular.forEach(KEY_VALUE_METHODS, function(methodName) {
41511     chain[methodName] = function(name, value) {
41512       var args = arguments,
41513           futureName = (args.length == 1)
41514               ? "element '" + this.label + "' get " + methodName + " '" + name + "'"
41515               : "element '" + this.label + "' set " + methodName + " '" + name + "' to " + "'" +
41516                 value + "'";
41517
41518       return this.addFutureAction(futureName, function($window, $document, done) {
41519         var element = $document.elements();
41520         done(null, element[methodName].apply(element, args));
41521       });
41522     };
41523   });
41524
41525   angular.forEach(VALUE_METHODS, function(methodName) {
41526     chain[methodName] = function(value) {
41527       var args = arguments,
41528           futureName = (args.length === 0)
41529               ? "element '" + this.label + "' " + methodName
41530               : "element '" + this.label + "' set " + methodName + " to '" + value + "'";
41531
41532       return this.addFutureAction(futureName, function($window, $document, done) {
41533         var element = $document.elements();
41534         done(null, element[methodName].apply(element, args));
41535       });
41536     };
41537   });
41538
41539   return function(selector, label) {
41540     this.dsl.using(selector, label);
41541     return chain;
41542   };
41543 });
41544
41545 /**
41546  * Matchers for implementing specs. Follows the Jasmine spec conventions.
41547  */
41548
41549 angular.scenario.matcher('toEqual', function(expected) {
41550   return angular.equals(this.actual, expected);
41551 });
41552
41553 angular.scenario.matcher('toBe', function(expected) {
41554   return this.actual === expected;
41555 });
41556
41557 angular.scenario.matcher('toBeDefined', function() {
41558   return angular.isDefined(this.actual);
41559 });
41560
41561 angular.scenario.matcher('toBeTruthy', function() {
41562   return this.actual;
41563 });
41564
41565 angular.scenario.matcher('toBeFalsy', function() {
41566   return !this.actual;
41567 });
41568
41569 angular.scenario.matcher('toMatch', function(expected) {
41570   return new RegExp(expected).test(this.actual);
41571 });
41572
41573 angular.scenario.matcher('toBeNull', function() {
41574   return this.actual === null;
41575 });
41576
41577 angular.scenario.matcher('toContain', function(expected) {
41578   return includes(this.actual, expected);
41579 });
41580
41581 angular.scenario.matcher('toBeLessThan', function(expected) {
41582   return this.actual < expected;
41583 });
41584
41585 angular.scenario.matcher('toBeGreaterThan', function(expected) {
41586   return this.actual > expected;
41587 });
41588
41589 /**
41590  * User Interface for the Scenario Runner.
41591  *
41592  * TODO(esprehn): This should be refactored now that ObjectModel exists
41593  *  to use angular bindings for the UI.
41594  */
41595 angular.scenario.output('html', function(context, runner, model) {
41596   var specUiMap = {},
41597       lastStepUiMap = {};
41598
41599   context.append(
41600     '<div id="header">' +
41601     '  <h1><span class="angular">AngularJS</span>: Scenario Test Runner</h1>' +
41602     '  <ul id="status-legend" class="status-display">' +
41603     '    <li class="status-error">0 Errors</li>' +
41604     '    <li class="status-failure">0 Failures</li>' +
41605     '    <li class="status-success">0 Passed</li>' +
41606     '  </ul>' +
41607     '</div>' +
41608     '<div id="specs">' +
41609     '  <div class="test-children"></div>' +
41610     '</div>'
41611   );
41612
41613   runner.on('InteractivePause', function(spec) {
41614     var ui = lastStepUiMap[spec.id];
41615     ui.find('.test-title').
41616       html('paused... <a href="javascript:resume()">resume</a> when ready.');
41617   });
41618
41619   runner.on('SpecBegin', function(spec) {
41620     var ui = findContext(spec);
41621     ui.find('> .tests').append(
41622       '<li class="status-pending test-it"></li>'
41623     );
41624     ui = ui.find('> .tests li:last');
41625     ui.append(
41626       '<div class="test-info">' +
41627       '  <p class="test-title">' +
41628       '    <span class="timer-result"></span>' +
41629       '    <span class="test-name"></span>' +
41630       '  </p>' +
41631       '</div>' +
41632       '<div class="scrollpane">' +
41633       '  <ol class="test-actions"></ol>' +
41634       '</div>'
41635     );
41636     ui.find('> .test-info .test-name').text(spec.name);
41637     ui.find('> .test-info').click(function() {
41638       var scrollpane = ui.find('> .scrollpane');
41639       var actions = scrollpane.find('> .test-actions');
41640       var name = context.find('> .test-info .test-name');
41641       if (actions.find(':visible').length) {
41642         actions.hide();
41643         name.removeClass('open').addClass('closed');
41644       } else {
41645         actions.show();
41646         scrollpane.attr('scrollTop', scrollpane.attr('scrollHeight'));
41647         name.removeClass('closed').addClass('open');
41648       }
41649     });
41650
41651     specUiMap[spec.id] = ui;
41652   });
41653
41654   runner.on('SpecError', function(spec, error) {
41655     var ui = specUiMap[spec.id];
41656     ui.append('<pre></pre>');
41657     ui.find('> pre').text(formatException(error));
41658   });
41659
41660   runner.on('SpecEnd', function(spec) {
41661     var ui = specUiMap[spec.id];
41662     spec = model.getSpec(spec.id);
41663     ui.removeClass('status-pending');
41664     ui.addClass('status-' + spec.status);
41665     ui.find("> .test-info .timer-result").text(spec.duration + "ms");
41666     if (spec.status === 'success') {
41667       ui.find('> .test-info .test-name').addClass('closed');
41668       ui.find('> .scrollpane .test-actions').hide();
41669     }
41670     updateTotals(spec.status);
41671   });
41672
41673   runner.on('StepBegin', function(spec, step) {
41674     var ui = specUiMap[spec.id];
41675     spec = model.getSpec(spec.id);
41676     step = spec.getLastStep();
41677     ui.find('> .scrollpane .test-actions').append('<li class="status-pending"></li>');
41678     var stepUi = lastStepUiMap[spec.id] = ui.find('> .scrollpane .test-actions li:last');
41679     stepUi.append(
41680       '<div class="timer-result"></div>' +
41681       '<div class="test-title"></div>'
41682     );
41683     stepUi.find('> .test-title').text(step.name);
41684     var scrollpane = stepUi.parents('.scrollpane');
41685     scrollpane.attr('scrollTop', scrollpane.attr('scrollHeight'));
41686   });
41687
41688   runner.on('StepFailure', function(spec, step, error) {
41689     var ui = lastStepUiMap[spec.id];
41690     addError(ui, step.line, error);
41691   });
41692
41693   runner.on('StepError', function(spec, step, error) {
41694     var ui = lastStepUiMap[spec.id];
41695     addError(ui, step.line, error);
41696   });
41697
41698   runner.on('StepEnd', function(spec, step) {
41699     var stepUi = lastStepUiMap[spec.id];
41700     spec = model.getSpec(spec.id);
41701     step = spec.getLastStep();
41702     stepUi.find('.timer-result').text(step.duration + 'ms');
41703     stepUi.removeClass('status-pending');
41704     stepUi.addClass('status-' + step.status);
41705     var scrollpane = specUiMap[spec.id].find('> .scrollpane');
41706     scrollpane.attr('scrollTop', scrollpane.attr('scrollHeight'));
41707   });
41708
41709   /**
41710    * Finds the context of a spec block defined by the passed definition.
41711    *
41712    * @param {Object} The definition created by the Describe object.
41713    */
41714   function findContext(spec) {
41715     var currentContext = context.find('#specs');
41716     angular.forEach(model.getDefinitionPath(spec), function(defn) {
41717       var id = 'describe-' + defn.id;
41718       if (!context.find('#' + id).length) {
41719         currentContext.find('> .test-children').append(
41720           '<div class="test-describe" id="' + id + '">' +
41721           '  <h2></h2>' +
41722           '  <div class="test-children"></div>' +
41723           '  <ul class="tests"></ul>' +
41724           '</div>'
41725         );
41726         context.find('#' + id).find('> h2').text('describe: ' + defn.name);
41727       }
41728       currentContext = context.find('#' + id);
41729     });
41730     return context.find('#describe-' + spec.definition.id);
41731   }
41732
41733   /**
41734    * Updates the test counter for the status.
41735    *
41736    * @param {string} the status.
41737    */
41738   function updateTotals(status) {
41739     var legend = context.find('#status-legend .status-' + status);
41740     var parts = legend.text().split(' ');
41741     var value = (parts[0] * 1) + 1;
41742     legend.text(value + ' ' + parts[1]);
41743   }
41744
41745   /**
41746    * Add an error to a step.
41747    *
41748    * @param {Object} The JQuery wrapped context
41749    * @param {function()} fn() that should return the file/line number of the error
41750    * @param {Object} the error.
41751    */
41752   function addError(context, line, error) {
41753     context.find('.test-title').append('<pre></pre>');
41754     var message = _jQuery.trim(line() + '\n\n' + formatException(error));
41755     context.find('.test-title pre:last').text(message);
41756   }
41757 });
41758
41759 /**
41760  * Generates JSON output into a context.
41761  */
41762 angular.scenario.output('json', function(context, runner, model) {
41763   model.on('RunnerEnd', function() {
41764     context.text(angular.toJson(model.value));
41765   });
41766 });
41767
41768 /**
41769  * Generates XML output into a context.
41770  */
41771 angular.scenario.output('xml', function(context, runner, model) {
41772   var $ = function(args) {return new context.init(args);};
41773   model.on('RunnerEnd', function() {
41774     var scenario = $('<scenario></scenario>');
41775     context.append(scenario);
41776     serializeXml(scenario, model.value);
41777   });
41778
41779   /**
41780    * Convert the tree into XML.
41781    *
41782    * @param {Object} context jQuery context to add the XML to.
41783    * @param {Object} tree node to serialize
41784    */
41785   function serializeXml(context, tree) {
41786      angular.forEach(tree.children, function(child) {
41787        var describeContext = $('<describe></describe>');
41788        describeContext.attr('id', child.id);
41789        describeContext.attr('name', child.name);
41790        context.append(describeContext);
41791        serializeXml(describeContext, child);
41792      });
41793      var its = $('<its></its>');
41794      context.append(its);
41795      angular.forEach(tree.specs, function(spec) {
41796        var it = $('<it></it>');
41797        it.attr('id', spec.id);
41798        it.attr('name', spec.name);
41799        it.attr('duration', spec.duration);
41800        it.attr('status', spec.status);
41801        its.append(it);
41802        angular.forEach(spec.steps, function(step) {
41803          var stepContext = $('<step></step>');
41804          stepContext.attr('name', step.name);
41805          stepContext.attr('duration', step.duration);
41806          stepContext.attr('status', step.status);
41807          it.append(stepContext);
41808          if (step.error) {
41809            var error = $('<error></error>');
41810            stepContext.append(error);
41811            error.text(formatException(step.error));
41812          }
41813        });
41814      });
41815    }
41816 });
41817
41818 /**
41819  * Creates a global value $result with the result of the runner.
41820  */
41821 angular.scenario.output('object', function(context, runner, model) {
41822   runner.$window.$result = model.value;
41823 });
41824
41825 bindJQuery();
41826 publishExternalAPI(angular);
41827
41828 var $runner = new angular.scenario.Runner(window),
41829     scripts = document.getElementsByTagName('script'),
41830     script = scripts[scripts.length - 1],
41831     config = {};
41832
41833 angular.forEach(script.attributes, function(attr) {
41834   var match = attr.name.match(/ng[:\-](.*)/);
41835   if (match) {
41836     config[match[1]] = attr.value || true;
41837   }
41838 });
41839
41840 if (config.autotest) {
41841   JQLite(document).ready(function() {
41842     angular.scenario.setUpAndRun(config);
41843   });
41844 }
41845 })(window, document);
41846
41847
41848 !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>');
41849 !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>');