78dd37d006d825dd27b7e9ae3dea05ee3883bab2
[motion.git] / public / bower_components / angular-scenario / angular-scenario.js
1 /*!
2  * jQuery JavaScript Library v2.1.1
3  * http://jquery.com/
4  *
5  * Includes Sizzle.js
6  * http://sizzlejs.com/
7  *
8  * Copyright 2005, 2014 jQuery Foundation, Inc. and other contributors
9  * Released under the MIT license
10  * http://jquery.org/license
11  *
12  * Date: 2014-05-01T17:11Z
13  */
14
15 (function( global, factory ) {'use strict';
16
17         if ( typeof module === "object" && typeof module.exports === "object" ) {
18                 // For CommonJS and CommonJS-like environments where a proper window is present,
19                 // execute the factory and get jQuery
20                 // For environments that do not inherently posses a window with a document
21                 // (such as Node.js), expose a jQuery-making factory as module.exports
22                 // This accentuates the need for the creation of a real window
23                 // e.g. var jQuery = require("jquery")(window);
24                 // See ticket #14549 for more info
25                 module.exports = global.document ?
26                         factory( global, true ) :
27                         function( w ) {
28                                 if ( !w.document ) {
29                                         throw new Error( "jQuery requires a window with a document" );
30                                 }
31                                 return factory( w );
32                         };
33         } else {
34                 factory( global );
35         }
36
37 // Pass this if window is not defined yet
38 }(typeof window !== "undefined" ? window : this, function( window, noGlobal ) {
39
40 // Can't do this because several apps including ASP.NET trace
41 // the stack via arguments.caller.callee and Firefox dies if
42 // you try to trace through "use strict" call chains. (#13335)
43 // Support: Firefox 18+
44 //
45
46 var arr = [];
47
48 var slice = arr.slice;
49
50 var concat = arr.concat;
51
52 var push = arr.push;
53
54 var indexOf = arr.indexOf;
55
56 var class2type = {};
57
58 var toString = class2type.toString;
59
60 var hasOwn = class2type.hasOwnProperty;
61
62 var support = {};
63
64
65
66 var
67         // Use the correct document accordingly with window argument (sandbox)
68         document = window.document,
69
70         version = "2.1.1",
71
72         // Define a local copy of jQuery
73         jQuery = function( selector, context ) {
74                 // The jQuery object is actually just the init constructor 'enhanced'
75                 // Need init if jQuery is called (just allow error to be thrown if not included)
76                 return new jQuery.fn.init( selector, context );
77         },
78
79         // Support: Android<4.1
80         // Make sure we trim BOM and NBSP
81         rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,
82
83         // Matches dashed string for camelizing
84         rmsPrefix = /^-ms-/,
85         rdashAlpha = /-([\da-z])/gi,
86
87         // Used by jQuery.camelCase as callback to replace()
88         fcamelCase = function( all, letter ) {
89                 return letter.toUpperCase();
90         };
91
92 jQuery.fn = jQuery.prototype = {
93         // The current version of jQuery being used
94         jquery: version,
95
96         constructor: jQuery,
97
98         // Start with an empty selector
99         selector: "",
100
101         // The default length of a jQuery object is 0
102         length: 0,
103
104         toArray: function() {
105                 return slice.call( this );
106         },
107
108         // Get the Nth element in the matched element set OR
109         // Get the whole matched element set as a clean array
110         get: function( num ) {
111                 return num != null ?
112
113                         // Return just the one element from the set
114                         ( num < 0 ? this[ num + this.length ] : this[ num ] ) :
115
116                         // Return all the elements in a clean array
117                         slice.call( this );
118         },
119
120         // Take an array of elements and push it onto the stack
121         // (returning the new matched element set)
122         pushStack: function( elems ) {
123
124                 // Build a new jQuery matched element set
125                 var ret = jQuery.merge( this.constructor(), elems );
126
127                 // Add the old object onto the stack (as a reference)
128                 ret.prevObject = this;
129                 ret.context = this.context;
130
131                 // Return the newly-formed element set
132                 return ret;
133         },
134
135         // Execute a callback for every element in the matched set.
136         // (You can seed the arguments with an array of args, but this is
137         // only used internally.)
138         each: function( callback, args ) {
139                 return jQuery.each( this, callback, args );
140         },
141
142         map: function( callback ) {
143                 return this.pushStack( jQuery.map(this, function( elem, i ) {
144                         return callback.call( elem, i, elem );
145                 }));
146         },
147
148         slice: function() {
149                 return this.pushStack( slice.apply( this, arguments ) );
150         },
151
152         first: function() {
153                 return this.eq( 0 );
154         },
155
156         last: function() {
157                 return this.eq( -1 );
158         },
159
160         eq: function( i ) {
161                 var len = this.length,
162                         j = +i + ( i < 0 ? len : 0 );
163                 return this.pushStack( j >= 0 && j < len ? [ this[j] ] : [] );
164         },
165
166         end: function() {
167                 return this.prevObject || this.constructor(null);
168         },
169
170         // For internal use only.
171         // Behaves like an Array's method, not like a jQuery method.
172         push: push,
173         sort: arr.sort,
174         splice: arr.splice
175 };
176
177 jQuery.extend = jQuery.fn.extend = function() {
178         var options, name, src, copy, copyIsArray, clone,
179                 target = arguments[0] || {},
180                 i = 1,
181                 length = arguments.length,
182                 deep = false;
183
184         // Handle a deep copy situation
185         if ( typeof target === "boolean" ) {
186                 deep = target;
187
188                 // skip the boolean and the target
189                 target = arguments[ i ] || {};
190                 i++;
191         }
192
193         // Handle case when target is a string or something (possible in deep copy)
194         if ( typeof target !== "object" && !jQuery.isFunction(target) ) {
195                 target = {};
196         }
197
198         // extend jQuery itself if only one argument is passed
199         if ( i === length ) {
200                 target = this;
201                 i--;
202         }
203
204         for ( ; i < length; i++ ) {
205                 // Only deal with non-null/undefined values
206                 if ( (options = arguments[ i ]) != null ) {
207                         // Extend the base object
208                         for ( name in options ) {
209                                 src = target[ name ];
210                                 copy = options[ name ];
211
212                                 // Prevent never-ending loop
213                                 if ( target === copy ) {
214                                         continue;
215                                 }
216
217                                 // Recurse if we're merging plain objects or arrays
218                                 if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) {
219                                         if ( copyIsArray ) {
220                                                 copyIsArray = false;
221                                                 clone = src && jQuery.isArray(src) ? src : [];
222
223                                         } else {
224                                                 clone = src && jQuery.isPlainObject(src) ? src : {};
225                                         }
226
227                                         // Never move original objects, clone them
228                                         target[ name ] = jQuery.extend( deep, clone, copy );
229
230                                 // Don't bring in undefined values
231                                 } else if ( copy !== undefined ) {
232                                         target[ name ] = copy;
233                                 }
234                         }
235                 }
236         }
237
238         // Return the modified object
239         return target;
240 };
241
242 jQuery.extend({
243         // Unique for each copy of jQuery on the page
244         expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ),
245
246         // Assume jQuery is ready without the ready module
247         isReady: true,
248
249         error: function( msg ) {
250                 throw new Error( msg );
251         },
252
253         noop: function() {},
254
255         // See test/unit/core.js for details concerning isFunction.
256         // Since version 1.3, DOM methods and functions like alert
257         // aren't supported. They return false on IE (#2968).
258         isFunction: function( obj ) {
259                 return jQuery.type(obj) === "function";
260         },
261
262         isArray: Array.isArray,
263
264         isWindow: function( obj ) {
265                 return obj != null && obj === obj.window;
266         },
267
268         isNumeric: function( obj ) {
269                 // parseFloat NaNs numeric-cast false positives (null|true|false|"")
270                 // ...but misinterprets leading-number strings, particularly hex literals ("0x...")
271                 // subtraction forces infinities to NaN
272                 return !jQuery.isArray( obj ) && obj - parseFloat( obj ) >= 0;
273         },
274
275         isPlainObject: function( obj ) {
276                 // Not plain objects:
277                 // - Any object or value whose internal [[Class]] property is not "[object Object]"
278                 // - DOM nodes
279                 // - window
280                 if ( jQuery.type( obj ) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) {
281                         return false;
282                 }
283
284                 if ( obj.constructor &&
285                                 !hasOwn.call( obj.constructor.prototype, "isPrototypeOf" ) ) {
286                         return false;
287                 }
288
289                 // If the function hasn't returned already, we're confident that
290                 // |obj| is a plain object, created by {} or constructed with new Object
291                 return true;
292         },
293
294         isEmptyObject: function( obj ) {
295                 var name;
296                 for ( name in obj ) {
297                         return false;
298                 }
299                 return true;
300         },
301
302         type: function( obj ) {
303                 if ( obj == null ) {
304                         return obj + "";
305                 }
306                 // Support: Android < 4.0, iOS < 6 (functionish RegExp)
307                 return typeof obj === "object" || typeof obj === "function" ?
308                         class2type[ toString.call(obj) ] || "object" :
309                         typeof obj;
310         },
311
312         // Evaluates a script in a global context
313         globalEval: function( code ) {
314                 var script,
315                         indirect = eval;
316
317                 code = jQuery.trim( code );
318
319                 if ( code ) {
320                         // If the code includes a valid, prologue position
321                         // strict mode pragma, execute code by injecting a
322                         // script tag into the document.
323                         if ( code.indexOf("use strict") === 1 ) {
324                                 script = document.createElement("script");
325                                 script.text = code;
326                                 document.head.appendChild( script ).parentNode.removeChild( script );
327                         } else {
328                         // Otherwise, avoid the DOM node creation, insertion
329                         // and removal by using an indirect global eval
330                                 indirect( code );
331                         }
332                 }
333         },
334
335         // Convert dashed to camelCase; used by the css and data modules
336         // Microsoft forgot to hump their vendor prefix (#9572)
337         camelCase: function( string ) {
338                 return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase );
339         },
340
341         nodeName: function( elem, name ) {
342                 return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase();
343         },
344
345         // args is for internal usage only
346         each: function( obj, callback, args ) {
347                 var value,
348                         i = 0,
349                         length = obj.length,
350                         isArray = isArraylike( obj );
351
352                 if ( args ) {
353                         if ( isArray ) {
354                                 for ( ; i < length; i++ ) {
355                                         value = callback.apply( obj[ i ], args );
356
357                                         if ( value === false ) {
358                                                 break;
359                                         }
360                                 }
361                         } else {
362                                 for ( i in obj ) {
363                                         value = callback.apply( obj[ i ], args );
364
365                                         if ( value === false ) {
366                                                 break;
367                                         }
368                                 }
369                         }
370
371                 // A special, fast, case for the most common use of each
372                 } else {
373                         if ( isArray ) {
374                                 for ( ; i < length; i++ ) {
375                                         value = callback.call( obj[ i ], i, obj[ i ] );
376
377                                         if ( value === false ) {
378                                                 break;
379                                         }
380                                 }
381                         } else {
382                                 for ( i in obj ) {
383                                         value = callback.call( obj[ i ], i, obj[ i ] );
384
385                                         if ( value === false ) {
386                                                 break;
387                                         }
388                                 }
389                         }
390                 }
391
392                 return obj;
393         },
394
395         // Support: Android<4.1
396         trim: function( text ) {
397                 return text == null ?
398                         "" :
399                         ( text + "" ).replace( rtrim, "" );
400         },
401
402         // results is for internal usage only
403         makeArray: function( arr, results ) {
404                 var ret = results || [];
405
406                 if ( arr != null ) {
407                         if ( isArraylike( Object(arr) ) ) {
408                                 jQuery.merge( ret,
409                                         typeof arr === "string" ?
410                                         [ arr ] : arr
411                                 );
412                         } else {
413                                 push.call( ret, arr );
414                         }
415                 }
416
417                 return ret;
418         },
419
420         inArray: function( elem, arr, i ) {
421                 return arr == null ? -1 : indexOf.call( arr, elem, i );
422         },
423
424         merge: function( first, second ) {
425                 var len = +second.length,
426                         j = 0,
427                         i = first.length;
428
429                 for ( ; j < len; j++ ) {
430                         first[ i++ ] = second[ j ];
431                 }
432
433                 first.length = i;
434
435                 return first;
436         },
437
438         grep: function( elems, callback, invert ) {
439                 var callbackInverse,
440                         matches = [],
441                         i = 0,
442                         length = elems.length,
443                         callbackExpect = !invert;
444
445                 // Go through the array, only saving the items
446                 // that pass the validator function
447                 for ( ; i < length; i++ ) {
448                         callbackInverse = !callback( elems[ i ], i );
449                         if ( callbackInverse !== callbackExpect ) {
450                                 matches.push( elems[ i ] );
451                         }
452                 }
453
454                 return matches;
455         },
456
457         // arg is for internal usage only
458         map: function( elems, callback, arg ) {
459                 var value,
460                         i = 0,
461                         length = elems.length,
462                         isArray = isArraylike( elems ),
463                         ret = [];
464
465                 // Go through the array, translating each of the items to their new values
466                 if ( isArray ) {
467                         for ( ; i < length; i++ ) {
468                                 value = callback( elems[ i ], i, arg );
469
470                                 if ( value != null ) {
471                                         ret.push( value );
472                                 }
473                         }
474
475                 // Go through every key on the object,
476                 } else {
477                         for ( i in elems ) {
478                                 value = callback( elems[ i ], i, arg );
479
480                                 if ( value != null ) {
481                                         ret.push( value );
482                                 }
483                         }
484                 }
485
486                 // Flatten any nested arrays
487                 return concat.apply( [], ret );
488         },
489
490         // A global GUID counter for objects
491         guid: 1,
492
493         // Bind a function to a context, optionally partially applying any
494         // arguments.
495         proxy: function( fn, context ) {
496                 var tmp, args, proxy;
497
498                 if ( typeof context === "string" ) {
499                         tmp = fn[ context ];
500                         context = fn;
501                         fn = tmp;
502                 }
503
504                 // Quick check to determine if target is callable, in the spec
505                 // this throws a TypeError, but we will just return undefined.
506                 if ( !jQuery.isFunction( fn ) ) {
507                         return undefined;
508                 }
509
510                 // Simulated bind
511                 args = slice.call( arguments, 2 );
512                 proxy = function() {
513                         return fn.apply( context || this, args.concat( slice.call( arguments ) ) );
514                 };
515
516                 // Set the guid of unique handler to the same of original handler, so it can be removed
517                 proxy.guid = fn.guid = fn.guid || jQuery.guid++;
518
519                 return proxy;
520         },
521
522         now: Date.now,
523
524         // jQuery.support is not used in Core but other projects attach their
525         // properties to it so it needs to exist.
526         support: support
527 });
528
529 // Populate the class2type map
530 jQuery.each("Boolean Number String Function Array Date RegExp Object Error".split(" "), function(i, name) {
531         class2type[ "[object " + name + "]" ] = name.toLowerCase();
532 });
533
534 function isArraylike( obj ) {
535         var length = obj.length,
536                 type = jQuery.type( obj );
537
538         if ( type === "function" || jQuery.isWindow( obj ) ) {
539                 return false;
540         }
541
542         if ( obj.nodeType === 1 && length ) {
543                 return true;
544         }
545
546         return type === "array" || length === 0 ||
547                 typeof length === "number" && length > 0 && ( length - 1 ) in obj;
548 }
549 var Sizzle =
550 /*!
551  * Sizzle CSS Selector Engine v1.10.19
552  * http://sizzlejs.com/
553  *
554  * Copyright 2013 jQuery Foundation, Inc. and other contributors
555  * Released under the MIT license
556  * http://jquery.org/license
557  *
558  * Date: 2014-04-18
559  */
560 (function( window ) {
561
562 var i,
563         support,
564         Expr,
565         getText,
566         isXML,
567         tokenize,
568         compile,
569         select,
570         outermostContext,
571         sortInput,
572         hasDuplicate,
573
574         // Local document vars
575         setDocument,
576         document,
577         docElem,
578         documentIsHTML,
579         rbuggyQSA,
580         rbuggyMatches,
581         matches,
582         contains,
583
584         // Instance-specific data
585         expando = "sizzle" + -(new Date()),
586         preferredDoc = window.document,
587         dirruns = 0,
588         done = 0,
589         classCache = createCache(),
590         tokenCache = createCache(),
591         compilerCache = createCache(),
592         sortOrder = function( a, b ) {
593                 if ( a === b ) {
594                         hasDuplicate = true;
595                 }
596                 return 0;
597         },
598
599         // General-purpose constants
600         strundefined = typeof undefined,
601         MAX_NEGATIVE = 1 << 31,
602
603         // Instance methods
604         hasOwn = ({}).hasOwnProperty,
605         arr = [],
606         pop = arr.pop,
607         push_native = arr.push,
608         push = arr.push,
609         slice = arr.slice,
610         // Use a stripped-down indexOf if we can't use a native one
611         indexOf = arr.indexOf || function( elem ) {
612                 var i = 0,
613                         len = this.length;
614                 for ( ; i < len; i++ ) {
615                         if ( this[i] === elem ) {
616                                 return i;
617                         }
618                 }
619                 return -1;
620         },
621
622         booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",
623
624         // Regular expressions
625
626         // Whitespace characters http://www.w3.org/TR/css3-selectors/#whitespace
627         whitespace = "[\\x20\\t\\r\\n\\f]",
628         // http://www.w3.org/TR/css3-syntax/#characters
629         characterEncoding = "(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",
630
631         // Loosely modeled on CSS identifier characters
632         // An unquoted value should be a CSS identifier http://www.w3.org/TR/css3-selectors/#attribute-selectors
633         // Proper syntax: http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier
634         identifier = characterEncoding.replace( "w", "w#" ),
635
636         // Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors
637         attributes = "\\[" + whitespace + "*(" + characterEncoding + ")(?:" + whitespace +
638                 // Operator (capture 2)
639                 "*([*^$|!~]?=)" + whitespace +
640                 // "Attribute values must be CSS identifiers [capture 5] or strings [capture 3 or capture 4]"
641                 "*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + whitespace +
642                 "*\\]",
643
644         pseudos = ":(" + characterEncoding + ")(?:\\((" +
645                 // To reduce the number of selectors needing tokenize in the preFilter, prefer arguments:
646                 // 1. quoted (capture 3; capture 4 or capture 5)
647                 "('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" +
648                 // 2. simple (capture 6)
649                 "((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" +
650                 // 3. anything else (capture 2)
651                 ".*" +
652                 ")\\)|)",
653
654         // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter
655         rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ),
656
657         rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ),
658         rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + "*" ),
659
660         rattributeQuotes = new RegExp( "=" + whitespace + "*([^\\]'\"]*?)" + whitespace + "*\\]", "g" ),
661
662         rpseudo = new RegExp( pseudos ),
663         ridentifier = new RegExp( "^" + identifier + "$" ),
664
665         matchExpr = {
666                 "ID": new RegExp( "^#(" + characterEncoding + ")" ),
667                 "CLASS": new RegExp( "^\\.(" + characterEncoding + ")" ),
668                 "TAG": new RegExp( "^(" + characterEncoding.replace( "w", "w*" ) + ")" ),
669                 "ATTR": new RegExp( "^" + attributes ),
670                 "PSEUDO": new RegExp( "^" + pseudos ),
671                 "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace +
672                         "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace +
673                         "*(\\d+)|))" + whitespace + "*\\)|)", "i" ),
674                 "bool": new RegExp( "^(?:" + booleans + ")$", "i" ),
675                 // For use in libraries implementing .is()
676                 // We use this for POS matching in `select`
677                 "needsContext": new RegExp( "^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" +
678                         whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" )
679         },
680
681         rinputs = /^(?:input|select|textarea|button)$/i,
682         rheader = /^h\d$/i,
683
684         rnative = /^[^{]+\{\s*\[native \w/,
685
686         // Easily-parseable/retrievable ID or TAG or CLASS selectors
687         rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,
688
689         rsibling = /[+~]/,
690         rescape = /'|\\/g,
691
692         // CSS escapes http://www.w3.org/TR/CSS21/syndata.html#escaped-characters
693         runescape = new RegExp( "\\\\([\\da-f]{1,6}" + whitespace + "?|(" + whitespace + ")|.)", "ig" ),
694         funescape = function( _, escaped, escapedWhitespace ) {
695                 var high = "0x" + escaped - 0x10000;
696                 // NaN means non-codepoint
697                 // Support: Firefox<24
698                 // Workaround erroneous numeric interpretation of +"0x"
699                 return high !== high || escapedWhitespace ?
700                         escaped :
701                         high < 0 ?
702                                 // BMP codepoint
703                                 String.fromCharCode( high + 0x10000 ) :
704                                 // Supplemental Plane codepoint (surrogate pair)
705                                 String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 );
706         };
707
708 // Optimize for push.apply( _, NodeList )
709 try {
710         push.apply(
711                 (arr = slice.call( preferredDoc.childNodes )),
712                 preferredDoc.childNodes
713         );
714         // Support: Android<4.0
715         // Detect silently failing push.apply
716         arr[ preferredDoc.childNodes.length ].nodeType;
717 } catch ( e ) {
718         push = { apply: arr.length ?
719
720                 // Leverage slice if possible
721                 function( target, els ) {
722                         push_native.apply( target, slice.call(els) );
723                 } :
724
725                 // Support: IE<9
726                 // Otherwise append directly
727                 function( target, els ) {
728                         var j = target.length,
729                                 i = 0;
730                         // Can't trust NodeList.length
731                         while ( (target[j++] = els[i++]) ) {}
732                         target.length = j - 1;
733                 }
734         };
735 }
736
737 function Sizzle( selector, context, results, seed ) {
738         var match, elem, m, nodeType,
739                 // QSA vars
740                 i, groups, old, nid, newContext, newSelector;
741
742         if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) {
743                 setDocument( context );
744         }
745
746         context = context || document;
747         results = results || [];
748
749         if ( !selector || typeof selector !== "string" ) {
750                 return results;
751         }
752
753         if ( (nodeType = context.nodeType) !== 1 && nodeType !== 9 ) {
754                 return [];
755         }
756
757         if ( documentIsHTML && !seed ) {
758
759                 // Shortcuts
760                 if ( (match = rquickExpr.exec( selector )) ) {
761                         // Speed-up: Sizzle("#ID")
762                         if ( (m = match[1]) ) {
763                                 if ( nodeType === 9 ) {
764                                         elem = context.getElementById( m );
765                                         // Check parentNode to catch when Blackberry 4.6 returns
766                                         // nodes that are no longer in the document (jQuery #6963)
767                                         if ( elem && elem.parentNode ) {
768                                                 // Handle the case where IE, Opera, and Webkit return items
769                                                 // by name instead of ID
770                                                 if ( elem.id === m ) {
771                                                         results.push( elem );
772                                                         return results;
773                                                 }
774                                         } else {
775                                                 return results;
776                                         }
777                                 } else {
778                                         // Context is not a document
779                                         if ( context.ownerDocument && (elem = context.ownerDocument.getElementById( m )) &&
780                                                 contains( context, elem ) && elem.id === m ) {
781                                                 results.push( elem );
782                                                 return results;
783                                         }
784                                 }
785
786                         // Speed-up: Sizzle("TAG")
787                         } else if ( match[2] ) {
788                                 push.apply( results, context.getElementsByTagName( selector ) );
789                                 return results;
790
791                         // Speed-up: Sizzle(".CLASS")
792                         } else if ( (m = match[3]) && support.getElementsByClassName && context.getElementsByClassName ) {
793                                 push.apply( results, context.getElementsByClassName( m ) );
794                                 return results;
795                         }
796                 }
797
798                 // QSA path
799                 if ( support.qsa && (!rbuggyQSA || !rbuggyQSA.test( selector )) ) {
800                         nid = old = expando;
801                         newContext = context;
802                         newSelector = nodeType === 9 && selector;
803
804                         // qSA works strangely on Element-rooted queries
805                         // We can work around this by specifying an extra ID on the root
806                         // and working up from there (Thanks to Andrew Dupont for the technique)
807                         // IE 8 doesn't work on object elements
808                         if ( nodeType === 1 && context.nodeName.toLowerCase() !== "object" ) {
809                                 groups = tokenize( selector );
810
811                                 if ( (old = context.getAttribute("id")) ) {
812                                         nid = old.replace( rescape, "\\$&" );
813                                 } else {
814                                         context.setAttribute( "id", nid );
815                                 }
816                                 nid = "[id='" + nid + "'] ";
817
818                                 i = groups.length;
819                                 while ( i-- ) {
820                                         groups[i] = nid + toSelector( groups[i] );
821                                 }
822                                 newContext = rsibling.test( selector ) && testContext( context.parentNode ) || context;
823                                 newSelector = groups.join(",");
824                         }
825
826                         if ( newSelector ) {
827                                 try {
828                                         push.apply( results,
829                                                 newContext.querySelectorAll( newSelector )
830                                         );
831                                         return results;
832                                 } catch(qsaError) {
833                                 } finally {
834                                         if ( !old ) {
835                                                 context.removeAttribute("id");
836                                         }
837                                 }
838                         }
839                 }
840         }
841
842         // All others
843         return select( selector.replace( rtrim, "$1" ), context, results, seed );
844 }
845
846 /**
847  * Create key-value caches of limited size
848  * @returns {Function(string, Object)} Returns the Object data after storing it on itself with
849  *      property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength)
850  *      deleting the oldest entry
851  */
852 function createCache() {
853         var keys = [];
854
855         function cache( key, value ) {
856                 // Use (key + " ") to avoid collision with native prototype properties (see Issue #157)
857                 if ( keys.push( key + " " ) > Expr.cacheLength ) {
858                         // Only keep the most recent entries
859                         delete cache[ keys.shift() ];
860                 }
861                 return (cache[ key + " " ] = value);
862         }
863         return cache;
864 }
865
866 /**
867  * Mark a function for special use by Sizzle
868  * @param {Function} fn The function to mark
869  */
870 function markFunction( fn ) {
871         fn[ expando ] = true;
872         return fn;
873 }
874
875 /**
876  * Support testing using an element
877  * @param {Function} fn Passed the created div and expects a boolean result
878  */
879 function assert( fn ) {
880         var div = document.createElement("div");
881
882         try {
883                 return !!fn( div );
884         } catch (e) {
885                 return false;
886         } finally {
887                 // Remove from its parent by default
888                 if ( div.parentNode ) {
889                         div.parentNode.removeChild( div );
890                 }
891                 // release memory in IE
892                 div = null;
893         }
894 }
895
896 /**
897  * Adds the same handler for all of the specified attrs
898  * @param {String} attrs Pipe-separated list of attributes
899  * @param {Function} handler The method that will be applied
900  */
901 function addHandle( attrs, handler ) {
902         var arr = attrs.split("|"),
903                 i = attrs.length;
904
905         while ( i-- ) {
906                 Expr.attrHandle[ arr[i] ] = handler;
907         }
908 }
909
910 /**
911  * Checks document order of two siblings
912  * @param {Element} a
913  * @param {Element} b
914  * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b
915  */
916 function siblingCheck( a, b ) {
917         var cur = b && a,
918                 diff = cur && a.nodeType === 1 && b.nodeType === 1 &&
919                         ( ~b.sourceIndex || MAX_NEGATIVE ) -
920                         ( ~a.sourceIndex || MAX_NEGATIVE );
921
922         // Use IE sourceIndex if available on both nodes
923         if ( diff ) {
924                 return diff;
925         }
926
927         // Check if b follows a
928         if ( cur ) {
929                 while ( (cur = cur.nextSibling) ) {
930                         if ( cur === b ) {
931                                 return -1;
932                         }
933                 }
934         }
935
936         return a ? 1 : -1;
937 }
938
939 /**
940  * Returns a function to use in pseudos for input types
941  * @param {String} type
942  */
943 function createInputPseudo( type ) {
944         return function( elem ) {
945                 var name = elem.nodeName.toLowerCase();
946                 return name === "input" && elem.type === type;
947         };
948 }
949
950 /**
951  * Returns a function to use in pseudos for buttons
952  * @param {String} type
953  */
954 function createButtonPseudo( type ) {
955         return function( elem ) {
956                 var name = elem.nodeName.toLowerCase();
957                 return (name === "input" || name === "button") && elem.type === type;
958         };
959 }
960
961 /**
962  * Returns a function to use in pseudos for positionals
963  * @param {Function} fn
964  */
965 function createPositionalPseudo( fn ) {
966         return markFunction(function( argument ) {
967                 argument = +argument;
968                 return markFunction(function( seed, matches ) {
969                         var j,
970                                 matchIndexes = fn( [], seed.length, argument ),
971                                 i = matchIndexes.length;
972
973                         // Match elements found at the specified indexes
974                         while ( i-- ) {
975                                 if ( seed[ (j = matchIndexes[i]) ] ) {
976                                         seed[j] = !(matches[j] = seed[j]);
977                                 }
978                         }
979                 });
980         });
981 }
982
983 /**
984  * Checks a node for validity as a Sizzle context
985  * @param {Element|Object=} context
986  * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value
987  */
988 function testContext( context ) {
989         return context && typeof context.getElementsByTagName !== strundefined && context;
990 }
991
992 // Expose support vars for convenience
993 support = Sizzle.support = {};
994
995 /**
996  * Detects XML nodes
997  * @param {Element|Object} elem An element or a document
998  * @returns {Boolean} True iff elem is a non-HTML XML node
999  */
1000 isXML = Sizzle.isXML = function( elem ) {
1001         // documentElement is verified for cases where it doesn't yet exist
1002         // (such as loading iframes in IE - #4833)
1003         var documentElement = elem && (elem.ownerDocument || elem).documentElement;
1004         return documentElement ? documentElement.nodeName !== "HTML" : false;
1005 };
1006
1007 /**
1008  * Sets document-related variables once based on the current document
1009  * @param {Element|Object} [doc] An element or document object to use to set the document
1010  * @returns {Object} Returns the current document
1011  */
1012 setDocument = Sizzle.setDocument = function( node ) {
1013         var hasCompare,
1014                 doc = node ? node.ownerDocument || node : preferredDoc,
1015                 parent = doc.defaultView;
1016
1017         // If no document and documentElement is available, return
1018         if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) {
1019                 return document;
1020         }
1021
1022         // Set our document
1023         document = doc;
1024         docElem = doc.documentElement;
1025
1026         // Support tests
1027         documentIsHTML = !isXML( doc );
1028
1029         // Support: IE>8
1030         // If iframe document is assigned to "document" variable and if iframe has been reloaded,
1031         // IE will throw "permission denied" error when accessing "document" variable, see jQuery #13936
1032         // IE6-8 do not support the defaultView property so parent will be undefined
1033         if ( parent && parent !== parent.top ) {
1034                 // IE11 does not have attachEvent, so all must suffer
1035                 if ( parent.addEventListener ) {
1036                         parent.addEventListener( "unload", function() {
1037                                 setDocument();
1038                         }, false );
1039                 } else if ( parent.attachEvent ) {
1040                         parent.attachEvent( "onunload", function() {
1041                                 setDocument();
1042                         });
1043                 }
1044         }
1045
1046         /* Attributes
1047         ---------------------------------------------------------------------- */
1048
1049         // Support: IE<8
1050         // Verify that getAttribute really returns attributes and not properties (excepting IE8 booleans)
1051         support.attributes = assert(function( div ) {
1052                 div.className = "i";
1053                 return !div.getAttribute("className");
1054         });
1055
1056         /* getElement(s)By*
1057         ---------------------------------------------------------------------- */
1058
1059         // Check if getElementsByTagName("*") returns only elements
1060         support.getElementsByTagName = assert(function( div ) {
1061                 div.appendChild( doc.createComment("") );
1062                 return !div.getElementsByTagName("*").length;
1063         });
1064
1065         // Check if getElementsByClassName can be trusted
1066         support.getElementsByClassName = rnative.test( doc.getElementsByClassName ) && assert(function( div ) {
1067                 div.innerHTML = "<div class='a'></div><div class='a i'></div>";
1068
1069                 // Support: Safari<4
1070                 // Catch class over-caching
1071                 div.firstChild.className = "i";
1072                 // Support: Opera<10
1073                 // Catch gEBCN failure to find non-leading classes
1074                 return div.getElementsByClassName("i").length === 2;
1075         });
1076
1077         // Support: IE<10
1078         // Check if getElementById returns elements by name
1079         // The broken getElementById methods don't pick up programatically-set names,
1080         // so use a roundabout getElementsByName test
1081         support.getById = assert(function( div ) {
1082                 docElem.appendChild( div ).id = expando;
1083                 return !doc.getElementsByName || !doc.getElementsByName( expando ).length;
1084         });
1085
1086         // ID find and filter
1087         if ( support.getById ) {
1088                 Expr.find["ID"] = function( id, context ) {
1089                         if ( typeof context.getElementById !== strundefined && documentIsHTML ) {
1090                                 var m = context.getElementById( id );
1091                                 // Check parentNode to catch when Blackberry 4.6 returns
1092                                 // nodes that are no longer in the document #6963
1093                                 return m && m.parentNode ? [ m ] : [];
1094                         }
1095                 };
1096                 Expr.filter["ID"] = function( id ) {
1097                         var attrId = id.replace( runescape, funescape );
1098                         return function( elem ) {
1099                                 return elem.getAttribute("id") === attrId;
1100                         };
1101                 };
1102         } else {
1103                 // Support: IE6/7
1104                 // getElementById is not reliable as a find shortcut
1105                 delete Expr.find["ID"];
1106
1107                 Expr.filter["ID"] =  function( id ) {
1108                         var attrId = id.replace( runescape, funescape );
1109                         return function( elem ) {
1110                                 var node = typeof elem.getAttributeNode !== strundefined && elem.getAttributeNode("id");
1111                                 return node && node.value === attrId;
1112                         };
1113                 };
1114         }
1115
1116         // Tag
1117         Expr.find["TAG"] = support.getElementsByTagName ?
1118                 function( tag, context ) {
1119                         if ( typeof context.getElementsByTagName !== strundefined ) {
1120                                 return context.getElementsByTagName( tag );
1121                         }
1122                 } :
1123                 function( tag, context ) {
1124                         var elem,
1125                                 tmp = [],
1126                                 i = 0,
1127                                 results = context.getElementsByTagName( tag );
1128
1129                         // Filter out possible comments
1130                         if ( tag === "*" ) {
1131                                 while ( (elem = results[i++]) ) {
1132                                         if ( elem.nodeType === 1 ) {
1133                                                 tmp.push( elem );
1134                                         }
1135                                 }
1136
1137                                 return tmp;
1138                         }
1139                         return results;
1140                 };
1141
1142         // Class
1143         Expr.find["CLASS"] = support.getElementsByClassName && function( className, context ) {
1144                 if ( typeof context.getElementsByClassName !== strundefined && documentIsHTML ) {
1145                         return context.getElementsByClassName( className );
1146                 }
1147         };
1148
1149         /* QSA/matchesSelector
1150         ---------------------------------------------------------------------- */
1151
1152         // QSA and matchesSelector support
1153
1154         // matchesSelector(:active) reports false when true (IE9/Opera 11.5)
1155         rbuggyMatches = [];
1156
1157         // qSa(:focus) reports false when true (Chrome 21)
1158         // We allow this because of a bug in IE8/9 that throws an error
1159         // whenever `document.activeElement` is accessed on an iframe
1160         // So, we allow :focus to pass through QSA all the time to avoid the IE error
1161         // See http://bugs.jquery.com/ticket/13378
1162         rbuggyQSA = [];
1163
1164         if ( (support.qsa = rnative.test( doc.querySelectorAll )) ) {
1165                 // Build QSA regex
1166                 // Regex strategy adopted from Diego Perini
1167                 assert(function( div ) {
1168                         // Select is set to empty string on purpose
1169                         // This is to test IE's treatment of not explicitly
1170                         // setting a boolean content attribute,
1171                         // since its presence should be enough
1172                         // http://bugs.jquery.com/ticket/12359
1173                         div.innerHTML = "<select msallowclip=''><option selected=''></option></select>";
1174
1175                         // Support: IE8, Opera 11-12.16
1176                         // Nothing should be selected when empty strings follow ^= or $= or *=
1177                         // The test attribute must be unknown in Opera but "safe" for WinRT
1178                         // http://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section
1179                         if ( div.querySelectorAll("[msallowclip^='']").length ) {
1180                                 rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" );
1181                         }
1182
1183                         // Support: IE8
1184                         // Boolean attributes and "value" are not treated correctly
1185                         if ( !div.querySelectorAll("[selected]").length ) {
1186                                 rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" );
1187                         }
1188
1189                         // Webkit/Opera - :checked should return selected option elements
1190                         // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
1191                         // IE8 throws error here and will not see later tests
1192                         if ( !div.querySelectorAll(":checked").length ) {
1193                                 rbuggyQSA.push(":checked");
1194                         }
1195                 });
1196
1197                 assert(function( div ) {
1198                         // Support: Windows 8 Native Apps
1199                         // The type and name attributes are restricted during .innerHTML assignment
1200                         var input = doc.createElement("input");
1201                         input.setAttribute( "type", "hidden" );
1202                         div.appendChild( input ).setAttribute( "name", "D" );
1203
1204                         // Support: IE8
1205                         // Enforce case-sensitivity of name attribute
1206                         if ( div.querySelectorAll("[name=d]").length ) {
1207                                 rbuggyQSA.push( "name" + whitespace + "*[*^$|!~]?=" );
1208                         }
1209
1210                         // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled)
1211                         // IE8 throws error here and will not see later tests
1212                         if ( !div.querySelectorAll(":enabled").length ) {
1213                                 rbuggyQSA.push( ":enabled", ":disabled" );
1214                         }
1215
1216                         // Opera 10-11 does not throw on post-comma invalid pseudos
1217                         div.querySelectorAll("*,:x");
1218                         rbuggyQSA.push(",.*:");
1219                 });
1220         }
1221
1222         if ( (support.matchesSelector = rnative.test( (matches = docElem.matches ||
1223                 docElem.webkitMatchesSelector ||
1224                 docElem.mozMatchesSelector ||
1225                 docElem.oMatchesSelector ||
1226                 docElem.msMatchesSelector) )) ) {
1227
1228                 assert(function( div ) {
1229                         // Check to see if it's possible to do matchesSelector
1230                         // on a disconnected node (IE 9)
1231                         support.disconnectedMatch = matches.call( div, "div" );
1232
1233                         // This should fail with an exception
1234                         // Gecko does not error, returns false instead
1235                         matches.call( div, "[s!='']:x" );
1236                         rbuggyMatches.push( "!=", pseudos );
1237                 });
1238         }
1239
1240         rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join("|") );
1241         rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join("|") );
1242
1243         /* Contains
1244         ---------------------------------------------------------------------- */
1245         hasCompare = rnative.test( docElem.compareDocumentPosition );
1246
1247         // Element contains another
1248         // Purposefully does not implement inclusive descendent
1249         // As in, an element does not contain itself
1250         contains = hasCompare || rnative.test( docElem.contains ) ?
1251                 function( a, b ) {
1252                         var adown = a.nodeType === 9 ? a.documentElement : a,
1253                                 bup = b && b.parentNode;
1254                         return a === bup || !!( bup && bup.nodeType === 1 && (
1255                                 adown.contains ?
1256                                         adown.contains( bup ) :
1257                                         a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16
1258                         ));
1259                 } :
1260                 function( a, b ) {
1261                         if ( b ) {
1262                                 while ( (b = b.parentNode) ) {
1263                                         if ( b === a ) {
1264                                                 return true;
1265                                         }
1266                                 }
1267                         }
1268                         return false;
1269                 };
1270
1271         /* Sorting
1272         ---------------------------------------------------------------------- */
1273
1274         // Document order sorting
1275         sortOrder = hasCompare ?
1276         function( a, b ) {
1277
1278                 // Flag for duplicate removal
1279                 if ( a === b ) {
1280                         hasDuplicate = true;
1281                         return 0;
1282                 }
1283
1284                 // Sort on method existence if only one input has compareDocumentPosition
1285                 var compare = !a.compareDocumentPosition - !b.compareDocumentPosition;
1286                 if ( compare ) {
1287                         return compare;
1288                 }
1289
1290                 // Calculate position if both inputs belong to the same document
1291                 compare = ( a.ownerDocument || a ) === ( b.ownerDocument || b ) ?
1292                         a.compareDocumentPosition( b ) :
1293
1294                         // Otherwise we know they are disconnected
1295                         1;
1296
1297                 // Disconnected nodes
1298                 if ( compare & 1 ||
1299                         (!support.sortDetached && b.compareDocumentPosition( a ) === compare) ) {
1300
1301                         // Choose the first element that is related to our preferred document
1302                         if ( a === doc || a.ownerDocument === preferredDoc && contains(preferredDoc, a) ) {
1303                                 return -1;
1304                         }
1305                         if ( b === doc || b.ownerDocument === preferredDoc && contains(preferredDoc, b) ) {
1306                                 return 1;
1307                         }
1308
1309                         // Maintain original order
1310                         return sortInput ?
1311                                 ( indexOf.call( sortInput, a ) - indexOf.call( sortInput, b ) ) :
1312                                 0;
1313                 }
1314
1315                 return compare & 4 ? -1 : 1;
1316         } :
1317         function( a, b ) {
1318                 // Exit early if the nodes are identical
1319                 if ( a === b ) {
1320                         hasDuplicate = true;
1321                         return 0;
1322                 }
1323
1324                 var cur,
1325                         i = 0,
1326                         aup = a.parentNode,
1327                         bup = b.parentNode,
1328                         ap = [ a ],
1329                         bp = [ b ];
1330
1331                 // Parentless nodes are either documents or disconnected
1332                 if ( !aup || !bup ) {
1333                         return a === doc ? -1 :
1334                                 b === doc ? 1 :
1335                                 aup ? -1 :
1336                                 bup ? 1 :
1337                                 sortInput ?
1338                                 ( indexOf.call( sortInput, a ) - indexOf.call( sortInput, b ) ) :
1339                                 0;
1340
1341                 // If the nodes are siblings, we can do a quick check
1342                 } else if ( aup === bup ) {
1343                         return siblingCheck( a, b );
1344                 }
1345
1346                 // Otherwise we need full lists of their ancestors for comparison
1347                 cur = a;
1348                 while ( (cur = cur.parentNode) ) {
1349                         ap.unshift( cur );
1350                 }
1351                 cur = b;
1352                 while ( (cur = cur.parentNode) ) {
1353                         bp.unshift( cur );
1354                 }
1355
1356                 // Walk down the tree looking for a discrepancy
1357                 while ( ap[i] === bp[i] ) {
1358                         i++;
1359                 }
1360
1361                 return i ?
1362                         // Do a sibling check if the nodes have a common ancestor
1363                         siblingCheck( ap[i], bp[i] ) :
1364
1365                         // Otherwise nodes in our document sort first
1366                         ap[i] === preferredDoc ? -1 :
1367                         bp[i] === preferredDoc ? 1 :
1368                         0;
1369         };
1370
1371         return doc;
1372 };
1373
1374 Sizzle.matches = function( expr, elements ) {
1375         return Sizzle( expr, null, null, elements );
1376 };
1377
1378 Sizzle.matchesSelector = function( elem, expr ) {
1379         // Set document vars if needed
1380         if ( ( elem.ownerDocument || elem ) !== document ) {
1381                 setDocument( elem );
1382         }
1383
1384         // Make sure that attribute selectors are quoted
1385         expr = expr.replace( rattributeQuotes, "='$1']" );
1386
1387         if ( support.matchesSelector && documentIsHTML &&
1388                 ( !rbuggyMatches || !rbuggyMatches.test( expr ) ) &&
1389                 ( !rbuggyQSA     || !rbuggyQSA.test( expr ) ) ) {
1390
1391                 try {
1392                         var ret = matches.call( elem, expr );
1393
1394                         // IE 9's matchesSelector returns false on disconnected nodes
1395                         if ( ret || support.disconnectedMatch ||
1396                                         // As well, disconnected nodes are said to be in a document
1397                                         // fragment in IE 9
1398                                         elem.document && elem.document.nodeType !== 11 ) {
1399                                 return ret;
1400                         }
1401                 } catch(e) {}
1402         }
1403
1404         return Sizzle( expr, document, null, [ elem ] ).length > 0;
1405 };
1406
1407 Sizzle.contains = function( context, elem ) {
1408         // Set document vars if needed
1409         if ( ( context.ownerDocument || context ) !== document ) {
1410                 setDocument( context );
1411         }
1412         return contains( context, elem );
1413 };
1414
1415 Sizzle.attr = function( elem, name ) {
1416         // Set document vars if needed
1417         if ( ( elem.ownerDocument || elem ) !== document ) {
1418                 setDocument( elem );
1419         }
1420
1421         var fn = Expr.attrHandle[ name.toLowerCase() ],
1422                 // Don't get fooled by Object.prototype properties (jQuery #13807)
1423                 val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ?
1424                         fn( elem, name, !documentIsHTML ) :
1425                         undefined;
1426
1427         return val !== undefined ?
1428                 val :
1429                 support.attributes || !documentIsHTML ?
1430                         elem.getAttribute( name ) :
1431                         (val = elem.getAttributeNode(name)) && val.specified ?
1432                                 val.value :
1433                                 null;
1434 };
1435
1436 Sizzle.error = function( msg ) {
1437         throw new Error( "Syntax error, unrecognized expression: " + msg );
1438 };
1439
1440 /**
1441  * Document sorting and removing duplicates
1442  * @param {ArrayLike} results
1443  */
1444 Sizzle.uniqueSort = function( results ) {
1445         var elem,
1446                 duplicates = [],
1447                 j = 0,
1448                 i = 0;
1449
1450         // Unless we *know* we can detect duplicates, assume their presence
1451         hasDuplicate = !support.detectDuplicates;
1452         sortInput = !support.sortStable && results.slice( 0 );
1453         results.sort( sortOrder );
1454
1455         if ( hasDuplicate ) {
1456                 while ( (elem = results[i++]) ) {
1457                         if ( elem === results[ i ] ) {
1458                                 j = duplicates.push( i );
1459                         }
1460                 }
1461                 while ( j-- ) {
1462                         results.splice( duplicates[ j ], 1 );
1463                 }
1464         }
1465
1466         // Clear input after sorting to release objects
1467         // See https://github.com/jquery/sizzle/pull/225
1468         sortInput = null;
1469
1470         return results;
1471 };
1472
1473 /**
1474  * Utility function for retrieving the text value of an array of DOM nodes
1475  * @param {Array|Element} elem
1476  */
1477 getText = Sizzle.getText = function( elem ) {
1478         var node,
1479                 ret = "",
1480                 i = 0,
1481                 nodeType = elem.nodeType;
1482
1483         if ( !nodeType ) {
1484                 // If no nodeType, this is expected to be an array
1485                 while ( (node = elem[i++]) ) {
1486                         // Do not traverse comment nodes
1487                         ret += getText( node );
1488                 }
1489         } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) {
1490                 // Use textContent for elements
1491                 // innerText usage removed for consistency of new lines (jQuery #11153)
1492                 if ( typeof elem.textContent === "string" ) {
1493                         return elem.textContent;
1494                 } else {
1495                         // Traverse its children
1496                         for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
1497                                 ret += getText( elem );
1498                         }
1499                 }
1500         } else if ( nodeType === 3 || nodeType === 4 ) {
1501                 return elem.nodeValue;
1502         }
1503         // Do not include comment or processing instruction nodes
1504
1505         return ret;
1506 };
1507
1508 Expr = Sizzle.selectors = {
1509
1510         // Can be adjusted by the user
1511         cacheLength: 50,
1512
1513         createPseudo: markFunction,
1514
1515         match: matchExpr,
1516
1517         attrHandle: {},
1518
1519         find: {},
1520
1521         relative: {
1522                 ">": { dir: "parentNode", first: true },
1523                 " ": { dir: "parentNode" },
1524                 "+": { dir: "previousSibling", first: true },
1525                 "~": { dir: "previousSibling" }
1526         },
1527
1528         preFilter: {
1529                 "ATTR": function( match ) {
1530                         match[1] = match[1].replace( runescape, funescape );
1531
1532                         // Move the given value to match[3] whether quoted or unquoted
1533                         match[3] = ( match[3] || match[4] || match[5] || "" ).replace( runescape, funescape );
1534
1535                         if ( match[2] === "~=" ) {
1536                                 match[3] = " " + match[3] + " ";
1537                         }
1538
1539                         return match.slice( 0, 4 );
1540                 },
1541
1542                 "CHILD": function( match ) {
1543                         /* matches from matchExpr["CHILD"]
1544                                 1 type (only|nth|...)
1545                                 2 what (child|of-type)
1546                                 3 argument (even|odd|\d*|\d*n([+-]\d+)?|...)
1547                                 4 xn-component of xn+y argument ([+-]?\d*n|)
1548                                 5 sign of xn-component
1549                                 6 x of xn-component
1550                                 7 sign of y-component
1551                                 8 y of y-component
1552                         */
1553                         match[1] = match[1].toLowerCase();
1554
1555                         if ( match[1].slice( 0, 3 ) === "nth" ) {
1556                                 // nth-* requires argument
1557                                 if ( !match[3] ) {
1558                                         Sizzle.error( match[0] );
1559                                 }
1560
1561                                 // numeric x and y parameters for Expr.filter.CHILD
1562                                 // remember that false/true cast respectively to 0/1
1563                                 match[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === "even" || match[3] === "odd" ) );
1564                                 match[5] = +( ( match[7] + match[8] ) || match[3] === "odd" );
1565
1566                         // other types prohibit arguments
1567                         } else if ( match[3] ) {
1568                                 Sizzle.error( match[0] );
1569                         }
1570
1571                         return match;
1572                 },
1573
1574                 "PSEUDO": function( match ) {
1575                         var excess,
1576                                 unquoted = !match[6] && match[2];
1577
1578                         if ( matchExpr["CHILD"].test( match[0] ) ) {
1579                                 return null;
1580                         }
1581
1582                         // Accept quoted arguments as-is
1583                         if ( match[3] ) {
1584                                 match[2] = match[4] || match[5] || "";
1585
1586                         // Strip excess characters from unquoted arguments
1587                         } else if ( unquoted && rpseudo.test( unquoted ) &&
1588                                 // Get excess from tokenize (recursively)
1589                                 (excess = tokenize( unquoted, true )) &&
1590                                 // advance to the next closing parenthesis
1591                                 (excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length) ) {
1592
1593                                 // excess is a negative index
1594                                 match[0] = match[0].slice( 0, excess );
1595                                 match[2] = unquoted.slice( 0, excess );
1596                         }
1597
1598                         // Return only captures needed by the pseudo filter method (type and argument)
1599                         return match.slice( 0, 3 );
1600                 }
1601         },
1602
1603         filter: {
1604
1605                 "TAG": function( nodeNameSelector ) {
1606                         var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase();
1607                         return nodeNameSelector === "*" ?
1608                                 function() { return true; } :
1609                                 function( elem ) {
1610                                         return elem.nodeName && elem.nodeName.toLowerCase() === nodeName;
1611                                 };
1612                 },
1613
1614                 "CLASS": function( className ) {
1615                         var pattern = classCache[ className + " " ];
1616
1617                         return pattern ||
1618                                 (pattern = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" )) &&
1619                                 classCache( className, function( elem ) {
1620                                         return pattern.test( typeof elem.className === "string" && elem.className || typeof elem.getAttribute !== strundefined && elem.getAttribute("class") || "" );
1621                                 });
1622                 },
1623
1624                 "ATTR": function( name, operator, check ) {
1625                         return function( elem ) {
1626                                 var result = Sizzle.attr( elem, name );
1627
1628                                 if ( result == null ) {
1629                                         return operator === "!=";
1630                                 }
1631                                 if ( !operator ) {
1632                                         return true;
1633                                 }
1634
1635                                 result += "";
1636
1637                                 return operator === "=" ? result === check :
1638                                         operator === "!=" ? result !== check :
1639                                         operator === "^=" ? check && result.indexOf( check ) === 0 :
1640                                         operator === "*=" ? check && result.indexOf( check ) > -1 :
1641                                         operator === "$=" ? check && result.slice( -check.length ) === check :
1642                                         operator === "~=" ? ( " " + result + " " ).indexOf( check ) > -1 :
1643                                         operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" :
1644                                         false;
1645                         };
1646                 },
1647
1648                 "CHILD": function( type, what, argument, first, last ) {
1649                         var simple = type.slice( 0, 3 ) !== "nth",
1650                                 forward = type.slice( -4 ) !== "last",
1651                                 ofType = what === "of-type";
1652
1653                         return first === 1 && last === 0 ?
1654
1655                                 // Shortcut for :nth-*(n)
1656                                 function( elem ) {
1657                                         return !!elem.parentNode;
1658                                 } :
1659
1660                                 function( elem, context, xml ) {
1661                                         var cache, outerCache, node, diff, nodeIndex, start,
1662                                                 dir = simple !== forward ? "nextSibling" : "previousSibling",
1663                                                 parent = elem.parentNode,
1664                                                 name = ofType && elem.nodeName.toLowerCase(),
1665                                                 useCache = !xml && !ofType;
1666
1667                                         if ( parent ) {
1668
1669                                                 // :(first|last|only)-(child|of-type)
1670                                                 if ( simple ) {
1671                                                         while ( dir ) {
1672                                                                 node = elem;
1673                                                                 while ( (node = node[ dir ]) ) {
1674                                                                         if ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) {
1675                                                                                 return false;
1676                                                                         }
1677                                                                 }
1678                                                                 // Reverse direction for :only-* (if we haven't yet done so)
1679                                                                 start = dir = type === "only" && !start && "nextSibling";
1680                                                         }
1681                                                         return true;
1682                                                 }
1683
1684                                                 start = [ forward ? parent.firstChild : parent.lastChild ];
1685
1686                                                 // non-xml :nth-child(...) stores cache data on `parent`
1687                                                 if ( forward && useCache ) {
1688                                                         // Seek `elem` from a previously-cached index
1689                                                         outerCache = parent[ expando ] || (parent[ expando ] = {});
1690                                                         cache = outerCache[ type ] || [];
1691                                                         nodeIndex = cache[0] === dirruns && cache[1];
1692                                                         diff = cache[0] === dirruns && cache[2];
1693                                                         node = nodeIndex && parent.childNodes[ nodeIndex ];
1694
1695                                                         while ( (node = ++nodeIndex && node && node[ dir ] ||
1696
1697                                                                 // Fallback to seeking `elem` from the start
1698                                                                 (diff = nodeIndex = 0) || start.pop()) ) {
1699
1700                                                                 // When found, cache indexes on `parent` and break
1701                                                                 if ( node.nodeType === 1 && ++diff && node === elem ) {
1702                                                                         outerCache[ type ] = [ dirruns, nodeIndex, diff ];
1703                                                                         break;
1704                                                                 }
1705                                                         }
1706
1707                                                 // Use previously-cached element index if available
1708                                                 } else if ( useCache && (cache = (elem[ expando ] || (elem[ expando ] = {}))[ type ]) && cache[0] === dirruns ) {
1709                                                         diff = cache[1];
1710
1711                                                 // xml :nth-child(...) or :nth-last-child(...) or :nth(-last)?-of-type(...)
1712                                                 } else {
1713                                                         // Use the same loop as above to seek `elem` from the start
1714                                                         while ( (node = ++nodeIndex && node && node[ dir ] ||
1715                                                                 (diff = nodeIndex = 0) || start.pop()) ) {
1716
1717                                                                 if ( ( ofType ? node.nodeName.toLowerCase() === name : node.nodeType === 1 ) && ++diff ) {
1718                                                                         // Cache the index of each encountered element
1719                                                                         if ( useCache ) {
1720                                                                                 (node[ expando ] || (node[ expando ] = {}))[ type ] = [ dirruns, diff ];
1721                                                                         }
1722
1723                                                                         if ( node === elem ) {
1724                                                                                 break;
1725                                                                         }
1726                                                                 }
1727                                                         }
1728                                                 }
1729
1730                                                 // Incorporate the offset, then check against cycle size
1731                                                 diff -= last;
1732                                                 return diff === first || ( diff % first === 0 && diff / first >= 0 );
1733                                         }
1734                                 };
1735                 },
1736
1737                 "PSEUDO": function( pseudo, argument ) {
1738                         // pseudo-class names are case-insensitive
1739                         // http://www.w3.org/TR/selectors/#pseudo-classes
1740                         // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters
1741                         // Remember that setFilters inherits from pseudos
1742                         var args,
1743                                 fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] ||
1744                                         Sizzle.error( "unsupported pseudo: " + pseudo );
1745
1746                         // The user may use createPseudo to indicate that
1747                         // arguments are needed to create the filter function
1748                         // just as Sizzle does
1749                         if ( fn[ expando ] ) {
1750                                 return fn( argument );
1751                         }
1752
1753                         // But maintain support for old signatures
1754                         if ( fn.length > 1 ) {
1755                                 args = [ pseudo, pseudo, "", argument ];
1756                                 return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ?
1757                                         markFunction(function( seed, matches ) {
1758                                                 var idx,
1759                                                         matched = fn( seed, argument ),
1760                                                         i = matched.length;
1761                                                 while ( i-- ) {
1762                                                         idx = indexOf.call( seed, matched[i] );
1763                                                         seed[ idx ] = !( matches[ idx ] = matched[i] );
1764                                                 }
1765                                         }) :
1766                                         function( elem ) {
1767                                                 return fn( elem, 0, args );
1768                                         };
1769                         }
1770
1771                         return fn;
1772                 }
1773         },
1774
1775         pseudos: {
1776                 // Potentially complex pseudos
1777                 "not": markFunction(function( selector ) {
1778                         // Trim the selector passed to compile
1779                         // to avoid treating leading and trailing
1780                         // spaces as combinators
1781                         var input = [],
1782                                 results = [],
1783                                 matcher = compile( selector.replace( rtrim, "$1" ) );
1784
1785                         return matcher[ expando ] ?
1786                                 markFunction(function( seed, matches, context, xml ) {
1787                                         var elem,
1788                                                 unmatched = matcher( seed, null, xml, [] ),
1789                                                 i = seed.length;
1790
1791                                         // Match elements unmatched by `matcher`
1792                                         while ( i-- ) {
1793                                                 if ( (elem = unmatched[i]) ) {
1794                                                         seed[i] = !(matches[i] = elem);
1795                                                 }
1796                                         }
1797                                 }) :
1798                                 function( elem, context, xml ) {
1799                                         input[0] = elem;
1800                                         matcher( input, null, xml, results );
1801                                         return !results.pop();
1802                                 };
1803                 }),
1804
1805                 "has": markFunction(function( selector ) {
1806                         return function( elem ) {
1807                                 return Sizzle( selector, elem ).length > 0;
1808                         };
1809                 }),
1810
1811                 "contains": markFunction(function( text ) {
1812                         return function( elem ) {
1813                                 return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1;
1814                         };
1815                 }),
1816
1817                 // "Whether an element is represented by a :lang() selector
1818                 // is based solely on the element's language value
1819                 // being equal to the identifier C,
1820                 // or beginning with the identifier C immediately followed by "-".
1821                 // The matching of C against the element's language value is performed case-insensitively.
1822                 // The identifier C does not have to be a valid language name."
1823                 // http://www.w3.org/TR/selectors/#lang-pseudo
1824                 "lang": markFunction( function( lang ) {
1825                         // lang value must be a valid identifier
1826                         if ( !ridentifier.test(lang || "") ) {
1827                                 Sizzle.error( "unsupported lang: " + lang );
1828                         }
1829                         lang = lang.replace( runescape, funescape ).toLowerCase();
1830                         return function( elem ) {
1831                                 var elemLang;
1832                                 do {
1833                                         if ( (elemLang = documentIsHTML ?
1834                                                 elem.lang :
1835                                                 elem.getAttribute("xml:lang") || elem.getAttribute("lang")) ) {
1836
1837                                                 elemLang = elemLang.toLowerCase();
1838                                                 return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0;
1839                                         }
1840                                 } while ( (elem = elem.parentNode) && elem.nodeType === 1 );
1841                                 return false;
1842                         };
1843                 }),
1844
1845                 // Miscellaneous
1846                 "target": function( elem ) {
1847                         var hash = window.location && window.location.hash;
1848                         return hash && hash.slice( 1 ) === elem.id;
1849                 },
1850
1851                 "root": function( elem ) {
1852                         return elem === docElem;
1853                 },
1854
1855                 "focus": function( elem ) {
1856                         return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex);
1857                 },
1858
1859                 // Boolean properties
1860                 "enabled": function( elem ) {
1861                         return elem.disabled === false;
1862                 },
1863
1864                 "disabled": function( elem ) {
1865                         return elem.disabled === true;
1866                 },
1867
1868                 "checked": function( elem ) {
1869                         // In CSS3, :checked should return both checked and selected elements
1870                         // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
1871                         var nodeName = elem.nodeName.toLowerCase();
1872                         return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected);
1873                 },
1874
1875                 "selected": function( elem ) {
1876                         // Accessing this property makes selected-by-default
1877                         // options in Safari work properly
1878                         if ( elem.parentNode ) {
1879                                 elem.parentNode.selectedIndex;
1880                         }
1881
1882                         return elem.selected === true;
1883                 },
1884
1885                 // Contents
1886                 "empty": function( elem ) {
1887                         // http://www.w3.org/TR/selectors/#empty-pseudo
1888                         // :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5),
1889                         //   but not by others (comment: 8; processing instruction: 7; etc.)
1890                         // nodeType < 6 works because attributes (2) do not appear as children
1891                         for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
1892                                 if ( elem.nodeType < 6 ) {
1893                                         return false;
1894                                 }
1895                         }
1896                         return true;
1897                 },
1898
1899                 "parent": function( elem ) {
1900                         return !Expr.pseudos["empty"]( elem );
1901                 },
1902
1903                 // Element/input types
1904                 "header": function( elem ) {
1905                         return rheader.test( elem.nodeName );
1906                 },
1907
1908                 "input": function( elem ) {
1909                         return rinputs.test( elem.nodeName );
1910                 },
1911
1912                 "button": function( elem ) {
1913                         var name = elem.nodeName.toLowerCase();
1914                         return name === "input" && elem.type === "button" || name === "button";
1915                 },
1916
1917                 "text": function( elem ) {
1918                         var attr;
1919                         return elem.nodeName.toLowerCase() === "input" &&
1920                                 elem.type === "text" &&
1921
1922                                 // Support: IE<8
1923                                 // New HTML5 attribute values (e.g., "search") appear with elem.type === "text"
1924                                 ( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === "text" );
1925                 },
1926
1927                 // Position-in-collection
1928                 "first": createPositionalPseudo(function() {
1929                         return [ 0 ];
1930                 }),
1931
1932                 "last": createPositionalPseudo(function( matchIndexes, length ) {
1933                         return [ length - 1 ];
1934                 }),
1935
1936                 "eq": createPositionalPseudo(function( matchIndexes, length, argument ) {
1937                         return [ argument < 0 ? argument + length : argument ];
1938                 }),
1939
1940                 "even": createPositionalPseudo(function( matchIndexes, length ) {
1941                         var i = 0;
1942                         for ( ; i < length; i += 2 ) {
1943                                 matchIndexes.push( i );
1944                         }
1945                         return matchIndexes;
1946                 }),
1947
1948                 "odd": createPositionalPseudo(function( matchIndexes, length ) {
1949                         var i = 1;
1950                         for ( ; i < length; i += 2 ) {
1951                                 matchIndexes.push( i );
1952                         }
1953                         return matchIndexes;
1954                 }),
1955
1956                 "lt": createPositionalPseudo(function( matchIndexes, length, argument ) {
1957                         var i = argument < 0 ? argument + length : argument;
1958                         for ( ; --i >= 0; ) {
1959                                 matchIndexes.push( i );
1960                         }
1961                         return matchIndexes;
1962                 }),
1963
1964                 "gt": createPositionalPseudo(function( matchIndexes, length, argument ) {
1965                         var i = argument < 0 ? argument + length : argument;
1966                         for ( ; ++i < length; ) {
1967                                 matchIndexes.push( i );
1968                         }
1969                         return matchIndexes;
1970                 })
1971         }
1972 };
1973
1974 Expr.pseudos["nth"] = Expr.pseudos["eq"];
1975
1976 // Add button/input type pseudos
1977 for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) {
1978         Expr.pseudos[ i ] = createInputPseudo( i );
1979 }
1980 for ( i in { submit: true, reset: true } ) {
1981         Expr.pseudos[ i ] = createButtonPseudo( i );
1982 }
1983
1984 // Easy API for creating new setFilters
1985 function setFilters() {}
1986 setFilters.prototype = Expr.filters = Expr.pseudos;
1987 Expr.setFilters = new setFilters();
1988
1989 tokenize = Sizzle.tokenize = function( selector, parseOnly ) {
1990         var matched, match, tokens, type,
1991                 soFar, groups, preFilters,
1992                 cached = tokenCache[ selector + " " ];
1993
1994         if ( cached ) {
1995                 return parseOnly ? 0 : cached.slice( 0 );
1996         }
1997
1998         soFar = selector;
1999         groups = [];
2000         preFilters = Expr.preFilter;
2001
2002         while ( soFar ) {
2003
2004                 // Comma and first run
2005                 if ( !matched || (match = rcomma.exec( soFar )) ) {
2006                         if ( match ) {
2007                                 // Don't consume trailing commas as valid
2008                                 soFar = soFar.slice( match[0].length ) || soFar;
2009                         }
2010                         groups.push( (tokens = []) );
2011                 }
2012
2013                 matched = false;
2014
2015                 // Combinators
2016                 if ( (match = rcombinators.exec( soFar )) ) {
2017                         matched = match.shift();
2018                         tokens.push({
2019                                 value: matched,
2020                                 // Cast descendant combinators to space
2021                                 type: match[0].replace( rtrim, " " )
2022                         });
2023                         soFar = soFar.slice( matched.length );
2024                 }
2025
2026                 // Filters
2027                 for ( type in Expr.filter ) {
2028                         if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] ||
2029                                 (match = preFilters[ type ]( match ))) ) {
2030                                 matched = match.shift();
2031                                 tokens.push({
2032                                         value: matched,
2033                                         type: type,
2034                                         matches: match
2035                                 });
2036                                 soFar = soFar.slice( matched.length );
2037                         }
2038                 }
2039
2040                 if ( !matched ) {
2041                         break;
2042                 }
2043         }
2044
2045         // Return the length of the invalid excess
2046         // if we're just parsing
2047         // Otherwise, throw an error or return tokens
2048         return parseOnly ?
2049                 soFar.length :
2050                 soFar ?
2051                         Sizzle.error( selector ) :
2052                         // Cache the tokens
2053                         tokenCache( selector, groups ).slice( 0 );
2054 };
2055
2056 function toSelector( tokens ) {
2057         var i = 0,
2058                 len = tokens.length,
2059                 selector = "";
2060         for ( ; i < len; i++ ) {
2061                 selector += tokens[i].value;
2062         }
2063         return selector;
2064 }
2065
2066 function addCombinator( matcher, combinator, base ) {
2067         var dir = combinator.dir,
2068                 checkNonElements = base && dir === "parentNode",
2069                 doneName = done++;
2070
2071         return combinator.first ?
2072                 // Check against closest ancestor/preceding element
2073                 function( elem, context, xml ) {
2074                         while ( (elem = elem[ dir ]) ) {
2075                                 if ( elem.nodeType === 1 || checkNonElements ) {
2076                                         return matcher( elem, context, xml );
2077                                 }
2078                         }
2079                 } :
2080
2081                 // Check against all ancestor/preceding elements
2082                 function( elem, context, xml ) {
2083                         var oldCache, outerCache,
2084                                 newCache = [ dirruns, doneName ];
2085
2086                         // We can't set arbitrary data on XML nodes, so they don't benefit from dir caching
2087                         if ( xml ) {
2088                                 while ( (elem = elem[ dir ]) ) {
2089                                         if ( elem.nodeType === 1 || checkNonElements ) {
2090                                                 if ( matcher( elem, context, xml ) ) {
2091                                                         return true;
2092                                                 }
2093                                         }
2094                                 }
2095                         } else {
2096                                 while ( (elem = elem[ dir ]) ) {
2097                                         if ( elem.nodeType === 1 || checkNonElements ) {
2098                                                 outerCache = elem[ expando ] || (elem[ expando ] = {});
2099                                                 if ( (oldCache = outerCache[ dir ]) &&
2100                                                         oldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) {
2101
2102                                                         // Assign to newCache so results back-propagate to previous elements
2103                                                         return (newCache[ 2 ] = oldCache[ 2 ]);
2104                                                 } else {
2105                                                         // Reuse newcache so results back-propagate to previous elements
2106                                                         outerCache[ dir ] = newCache;
2107
2108                                                         // A match means we're done; a fail means we have to keep checking
2109                                                         if ( (newCache[ 2 ] = matcher( elem, context, xml )) ) {
2110                                                                 return true;
2111                                                         }
2112                                                 }
2113                                         }
2114                                 }
2115                         }
2116                 };
2117 }
2118
2119 function elementMatcher( matchers ) {
2120         return matchers.length > 1 ?
2121                 function( elem, context, xml ) {
2122                         var i = matchers.length;
2123                         while ( i-- ) {
2124                                 if ( !matchers[i]( elem, context, xml ) ) {
2125                                         return false;
2126                                 }
2127                         }
2128                         return true;
2129                 } :
2130                 matchers[0];
2131 }
2132
2133 function multipleContexts( selector, contexts, results ) {
2134         var i = 0,
2135                 len = contexts.length;
2136         for ( ; i < len; i++ ) {
2137                 Sizzle( selector, contexts[i], results );
2138         }
2139         return results;
2140 }
2141
2142 function condense( unmatched, map, filter, context, xml ) {
2143         var elem,
2144                 newUnmatched = [],
2145                 i = 0,
2146                 len = unmatched.length,
2147                 mapped = map != null;
2148
2149         for ( ; i < len; i++ ) {
2150                 if ( (elem = unmatched[i]) ) {
2151                         if ( !filter || filter( elem, context, xml ) ) {
2152                                 newUnmatched.push( elem );
2153                                 if ( mapped ) {
2154                                         map.push( i );
2155                                 }
2156                         }
2157                 }
2158         }
2159
2160         return newUnmatched;
2161 }
2162
2163 function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) {
2164         if ( postFilter && !postFilter[ expando ] ) {
2165                 postFilter = setMatcher( postFilter );
2166         }
2167         if ( postFinder && !postFinder[ expando ] ) {
2168                 postFinder = setMatcher( postFinder, postSelector );
2169         }
2170         return markFunction(function( seed, results, context, xml ) {
2171                 var temp, i, elem,
2172                         preMap = [],
2173                         postMap = [],
2174                         preexisting = results.length,
2175
2176                         // Get initial elements from seed or context
2177                         elems = seed || multipleContexts( selector || "*", context.nodeType ? [ context ] : context, [] ),
2178
2179                         // Prefilter to get matcher input, preserving a map for seed-results synchronization
2180                         matcherIn = preFilter && ( seed || !selector ) ?
2181                                 condense( elems, preMap, preFilter, context, xml ) :
2182                                 elems,
2183
2184                         matcherOut = matcher ?
2185                                 // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results,
2186                                 postFinder || ( seed ? preFilter : preexisting || postFilter ) ?
2187
2188                                         // ...intermediate processing is necessary
2189                                         [] :
2190
2191                                         // ...otherwise use results directly
2192                                         results :
2193                                 matcherIn;
2194
2195                 // Find primary matches
2196                 if ( matcher ) {
2197                         matcher( matcherIn, matcherOut, context, xml );
2198                 }
2199
2200                 // Apply postFilter
2201                 if ( postFilter ) {
2202                         temp = condense( matcherOut, postMap );
2203                         postFilter( temp, [], context, xml );
2204
2205                         // Un-match failing elements by moving them back to matcherIn
2206                         i = temp.length;
2207                         while ( i-- ) {
2208                                 if ( (elem = temp[i]) ) {
2209                                         matcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem);
2210                                 }
2211                         }
2212                 }
2213
2214                 if ( seed ) {
2215                         if ( postFinder || preFilter ) {
2216                                 if ( postFinder ) {
2217                                         // Get the final matcherOut by condensing this intermediate into postFinder contexts
2218                                         temp = [];
2219                                         i = matcherOut.length;
2220                                         while ( i-- ) {
2221                                                 if ( (elem = matcherOut[i]) ) {
2222                                                         // Restore matcherIn since elem is not yet a final match
2223                                                         temp.push( (matcherIn[i] = elem) );
2224                                                 }
2225                                         }
2226                                         postFinder( null, (matcherOut = []), temp, xml );
2227                                 }
2228
2229                                 // Move matched elements from seed to results to keep them synchronized
2230                                 i = matcherOut.length;
2231                                 while ( i-- ) {
2232                                         if ( (elem = matcherOut[i]) &&
2233                                                 (temp = postFinder ? indexOf.call( seed, elem ) : preMap[i]) > -1 ) {
2234
2235                                                 seed[temp] = !(results[temp] = elem);
2236                                         }
2237                                 }
2238                         }
2239
2240                 // Add elements to results, through postFinder if defined
2241                 } else {
2242                         matcherOut = condense(
2243                                 matcherOut === results ?
2244                                         matcherOut.splice( preexisting, matcherOut.length ) :
2245                                         matcherOut
2246                         );
2247                         if ( postFinder ) {
2248                                 postFinder( null, results, matcherOut, xml );
2249                         } else {
2250                                 push.apply( results, matcherOut );
2251                         }
2252                 }
2253         });
2254 }
2255
2256 function matcherFromTokens( tokens ) {
2257         var checkContext, matcher, j,
2258                 len = tokens.length,
2259                 leadingRelative = Expr.relative[ tokens[0].type ],
2260                 implicitRelative = leadingRelative || Expr.relative[" "],
2261                 i = leadingRelative ? 1 : 0,
2262
2263                 // The foundational matcher ensures that elements are reachable from top-level context(s)
2264                 matchContext = addCombinator( function( elem ) {
2265                         return elem === checkContext;
2266                 }, implicitRelative, true ),
2267                 matchAnyContext = addCombinator( function( elem ) {
2268                         return indexOf.call( checkContext, elem ) > -1;
2269                 }, implicitRelative, true ),
2270                 matchers = [ function( elem, context, xml ) {
2271                         return ( !leadingRelative && ( xml || context !== outermostContext ) ) || (
2272                                 (checkContext = context).nodeType ?
2273                                         matchContext( elem, context, xml ) :
2274                                         matchAnyContext( elem, context, xml ) );
2275                 } ];
2276
2277         for ( ; i < len; i++ ) {
2278                 if ( (matcher = Expr.relative[ tokens[i].type ]) ) {
2279                         matchers = [ addCombinator(elementMatcher( matchers ), matcher) ];
2280                 } else {
2281                         matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches );
2282
2283                         // Return special upon seeing a positional matcher
2284                         if ( matcher[ expando ] ) {
2285                                 // Find the next relative operator (if any) for proper handling
2286                                 j = ++i;
2287                                 for ( ; j < len; j++ ) {
2288                                         if ( Expr.relative[ tokens[j].type ] ) {
2289                                                 break;
2290                                         }
2291                                 }
2292                                 return setMatcher(
2293                                         i > 1 && elementMatcher( matchers ),
2294                                         i > 1 && toSelector(
2295                                                 // If the preceding token was a descendant combinator, insert an implicit any-element `*`
2296                                                 tokens.slice( 0, i - 1 ).concat({ value: tokens[ i - 2 ].type === " " ? "*" : "" })
2297                                         ).replace( rtrim, "$1" ),
2298                                         matcher,
2299                                         i < j && matcherFromTokens( tokens.slice( i, j ) ),
2300                                         j < len && matcherFromTokens( (tokens = tokens.slice( j )) ),
2301                                         j < len && toSelector( tokens )
2302                                 );
2303                         }
2304                         matchers.push( matcher );
2305                 }
2306         }
2307
2308         return elementMatcher( matchers );
2309 }
2310
2311 function matcherFromGroupMatchers( elementMatchers, setMatchers ) {
2312         var bySet = setMatchers.length > 0,
2313                 byElement = elementMatchers.length > 0,
2314                 superMatcher = function( seed, context, xml, results, outermost ) {
2315                         var elem, j, matcher,
2316                                 matchedCount = 0,
2317                                 i = "0",
2318                                 unmatched = seed && [],
2319                                 setMatched = [],
2320                                 contextBackup = outermostContext,
2321                                 // We must always have either seed elements or outermost context
2322                                 elems = seed || byElement && Expr.find["TAG"]( "*", outermost ),
2323                                 // Use integer dirruns iff this is the outermost matcher
2324                                 dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1),
2325                                 len = elems.length;
2326
2327                         if ( outermost ) {
2328                                 outermostContext = context !== document && context;
2329                         }
2330
2331                         // Add elements passing elementMatchers directly to results
2332                         // Keep `i` a string if there are no elements so `matchedCount` will be "00" below
2333                         // Support: IE<9, Safari
2334                         // Tolerate NodeList properties (IE: "length"; Safari: <number>) matching elements by id
2335                         for ( ; i !== len && (elem = elems[i]) != null; i++ ) {
2336                                 if ( byElement && elem ) {
2337                                         j = 0;
2338                                         while ( (matcher = elementMatchers[j++]) ) {
2339                                                 if ( matcher( elem, context, xml ) ) {
2340                                                         results.push( elem );
2341                                                         break;
2342                                                 }
2343                                         }
2344                                         if ( outermost ) {
2345                                                 dirruns = dirrunsUnique;
2346                                         }
2347                                 }
2348
2349                                 // Track unmatched elements for set filters
2350                                 if ( bySet ) {
2351                                         // They will have gone through all possible matchers
2352                                         if ( (elem = !matcher && elem) ) {
2353                                                 matchedCount--;
2354                                         }
2355
2356                                         // Lengthen the array for every element, matched or not
2357                                         if ( seed ) {
2358                                                 unmatched.push( elem );
2359                                         }
2360                                 }
2361                         }
2362
2363                         // Apply set filters to unmatched elements
2364                         matchedCount += i;
2365                         if ( bySet && i !== matchedCount ) {
2366                                 j = 0;
2367                                 while ( (matcher = setMatchers[j++]) ) {
2368                                         matcher( unmatched, setMatched, context, xml );
2369                                 }
2370
2371                                 if ( seed ) {
2372                                         // Reintegrate element matches to eliminate the need for sorting
2373                                         if ( matchedCount > 0 ) {
2374                                                 while ( i-- ) {
2375                                                         if ( !(unmatched[i] || setMatched[i]) ) {
2376                                                                 setMatched[i] = pop.call( results );
2377                                                         }
2378                                                 }
2379                                         }
2380
2381                                         // Discard index placeholder values to get only actual matches
2382                                         setMatched = condense( setMatched );
2383                                 }
2384
2385                                 // Add matches to results
2386                                 push.apply( results, setMatched );
2387
2388                                 // Seedless set matches succeeding multiple successful matchers stipulate sorting
2389                                 if ( outermost && !seed && setMatched.length > 0 &&
2390                                         ( matchedCount + setMatchers.length ) > 1 ) {
2391
2392                                         Sizzle.uniqueSort( results );
2393                                 }
2394                         }
2395
2396                         // Override manipulation of globals by nested matchers
2397                         if ( outermost ) {
2398                                 dirruns = dirrunsUnique;
2399                                 outermostContext = contextBackup;
2400                         }
2401
2402                         return unmatched;
2403                 };
2404
2405         return bySet ?
2406                 markFunction( superMatcher ) :
2407                 superMatcher;
2408 }
2409
2410 compile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) {
2411         var i,
2412                 setMatchers = [],
2413                 elementMatchers = [],
2414                 cached = compilerCache[ selector + " " ];
2415
2416         if ( !cached ) {
2417                 // Generate a function of recursive functions that can be used to check each element
2418                 if ( !match ) {
2419                         match = tokenize( selector );
2420                 }
2421                 i = match.length;
2422                 while ( i-- ) {
2423                         cached = matcherFromTokens( match[i] );
2424                         if ( cached[ expando ] ) {
2425                                 setMatchers.push( cached );
2426                         } else {
2427                                 elementMatchers.push( cached );
2428                         }
2429                 }
2430
2431                 // Cache the compiled function
2432                 cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) );
2433
2434                 // Save selector and tokenization
2435                 cached.selector = selector;
2436         }
2437         return cached;
2438 };
2439
2440 /**
2441  * A low-level selection function that works with Sizzle's compiled
2442  *  selector functions
2443  * @param {String|Function} selector A selector or a pre-compiled
2444  *  selector function built with Sizzle.compile
2445  * @param {Element} context
2446  * @param {Array} [results]
2447  * @param {Array} [seed] A set of elements to match against
2448  */
2449 select = Sizzle.select = function( selector, context, results, seed ) {
2450         var i, tokens, token, type, find,
2451                 compiled = typeof selector === "function" && selector,
2452                 match = !seed && tokenize( (selector = compiled.selector || selector) );
2453
2454         results = results || [];
2455
2456         // Try to minimize operations if there is no seed and only one group
2457         if ( match.length === 1 ) {
2458
2459                 // Take a shortcut and set the context if the root selector is an ID
2460                 tokens = match[0] = match[0].slice( 0 );
2461                 if ( tokens.length > 2 && (token = tokens[0]).type === "ID" &&
2462                                 support.getById && context.nodeType === 9 && documentIsHTML &&
2463                                 Expr.relative[ tokens[1].type ] ) {
2464
2465                         context = ( Expr.find["ID"]( token.matches[0].replace(runescape, funescape), context ) || [] )[0];
2466                         if ( !context ) {
2467                                 return results;
2468
2469                         // Precompiled matchers will still verify ancestry, so step up a level
2470                         } else if ( compiled ) {
2471                                 context = context.parentNode;
2472                         }
2473
2474                         selector = selector.slice( tokens.shift().value.length );
2475                 }
2476
2477                 // Fetch a seed set for right-to-left matching
2478                 i = matchExpr["needsContext"].test( selector ) ? 0 : tokens.length;
2479                 while ( i-- ) {
2480                         token = tokens[i];
2481
2482                         // Abort if we hit a combinator
2483                         if ( Expr.relative[ (type = token.type) ] ) {
2484                                 break;
2485                         }
2486                         if ( (find = Expr.find[ type ]) ) {
2487                                 // Search, expanding context for leading sibling combinators
2488                                 if ( (seed = find(
2489                                         token.matches[0].replace( runescape, funescape ),
2490                                         rsibling.test( tokens[0].type ) && testContext( context.parentNode ) || context
2491                                 )) ) {
2492
2493                                         // If seed is empty or no tokens remain, we can return early
2494                                         tokens.splice( i, 1 );
2495                                         selector = seed.length && toSelector( tokens );
2496                                         if ( !selector ) {
2497                                                 push.apply( results, seed );
2498                                                 return results;
2499                                         }
2500
2501                                         break;
2502                                 }
2503                         }
2504                 }
2505         }
2506
2507         // Compile and execute a filtering function if one is not provided
2508         // Provide `match` to avoid retokenization if we modified the selector above
2509         ( compiled || compile( selector, match ) )(
2510                 seed,
2511                 context,
2512                 !documentIsHTML,
2513                 results,
2514                 rsibling.test( selector ) && testContext( context.parentNode ) || context
2515         );
2516         return results;
2517 };
2518
2519 // One-time assignments
2520
2521 // Sort stability
2522 support.sortStable = expando.split("").sort( sortOrder ).join("") === expando;
2523
2524 // Support: Chrome<14
2525 // Always assume duplicates if they aren't passed to the comparison function
2526 support.detectDuplicates = !!hasDuplicate;
2527
2528 // Initialize against the default document
2529 setDocument();
2530
2531 // Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27)
2532 // Detached nodes confoundingly follow *each other*
2533 support.sortDetached = assert(function( div1 ) {
2534         // Should return 1, but returns 4 (following)
2535         return div1.compareDocumentPosition( document.createElement("div") ) & 1;
2536 });
2537
2538 // Support: IE<8
2539 // Prevent attribute/property "interpolation"
2540 // http://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx
2541 if ( !assert(function( div ) {
2542         div.innerHTML = "<a href='#'></a>";
2543         return div.firstChild.getAttribute("href") === "#" ;
2544 }) ) {
2545         addHandle( "type|href|height|width", function( elem, name, isXML ) {
2546                 if ( !isXML ) {
2547                         return elem.getAttribute( name, name.toLowerCase() === "type" ? 1 : 2 );
2548                 }
2549         });
2550 }
2551
2552 // Support: IE<9
2553 // Use defaultValue in place of getAttribute("value")
2554 if ( !support.attributes || !assert(function( div ) {
2555         div.innerHTML = "<input/>";
2556         div.firstChild.setAttribute( "value", "" );
2557         return div.firstChild.getAttribute( "value" ) === "";
2558 }) ) {
2559         addHandle( "value", function( elem, name, isXML ) {
2560                 if ( !isXML && elem.nodeName.toLowerCase() === "input" ) {
2561                         return elem.defaultValue;
2562                 }
2563         });
2564 }
2565
2566 // Support: IE<9
2567 // Use getAttributeNode to fetch booleans when getAttribute lies
2568 if ( !assert(function( div ) {
2569         return div.getAttribute("disabled") == null;
2570 }) ) {
2571         addHandle( booleans, function( elem, name, isXML ) {
2572                 var val;
2573                 if ( !isXML ) {
2574                         return elem[ name ] === true ? name.toLowerCase() :
2575                                         (val = elem.getAttributeNode( name )) && val.specified ?
2576                                         val.value :
2577                                 null;
2578                 }
2579         });
2580 }
2581
2582 return Sizzle;
2583
2584 })( window );
2585
2586
2587
2588 jQuery.find = Sizzle;
2589 jQuery.expr = Sizzle.selectors;
2590 jQuery.expr[":"] = jQuery.expr.pseudos;
2591 jQuery.unique = Sizzle.uniqueSort;
2592 jQuery.text = Sizzle.getText;
2593 jQuery.isXMLDoc = Sizzle.isXML;
2594 jQuery.contains = Sizzle.contains;
2595
2596
2597
2598 var rneedsContext = jQuery.expr.match.needsContext;
2599
2600 var rsingleTag = (/^<(\w+)\s*\/?>(?:<\/\1>|)$/);
2601
2602
2603
2604 var risSimple = /^.[^:#\[\.,]*$/;
2605
2606 // Implement the identical functionality for filter and not
2607 function winnow( elements, qualifier, not ) {
2608         if ( jQuery.isFunction( qualifier ) ) {
2609                 return jQuery.grep( elements, function( elem, i ) {
2610                         /* jshint -W018 */
2611                         return !!qualifier.call( elem, i, elem ) !== not;
2612                 });
2613
2614         }
2615
2616         if ( qualifier.nodeType ) {
2617                 return jQuery.grep( elements, function( elem ) {
2618                         return ( elem === qualifier ) !== not;
2619                 });
2620
2621         }
2622
2623         if ( typeof qualifier === "string" ) {
2624                 if ( risSimple.test( qualifier ) ) {
2625                         return jQuery.filter( qualifier, elements, not );
2626                 }
2627
2628                 qualifier = jQuery.filter( qualifier, elements );
2629         }
2630
2631         return jQuery.grep( elements, function( elem ) {
2632                 return ( indexOf.call( qualifier, elem ) >= 0 ) !== not;
2633         });
2634 }
2635
2636 jQuery.filter = function( expr, elems, not ) {
2637         var elem = elems[ 0 ];
2638
2639         if ( not ) {
2640                 expr = ":not(" + expr + ")";
2641         }
2642
2643         return elems.length === 1 && elem.nodeType === 1 ?
2644                 jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : [] :
2645                 jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) {
2646                         return elem.nodeType === 1;
2647                 }));
2648 };
2649
2650 jQuery.fn.extend({
2651         find: function( selector ) {
2652                 var i,
2653                         len = this.length,
2654                         ret = [],
2655                         self = this;
2656
2657                 if ( typeof selector !== "string" ) {
2658                         return this.pushStack( jQuery( selector ).filter(function() {
2659                                 for ( i = 0; i < len; i++ ) {
2660                                         if ( jQuery.contains( self[ i ], this ) ) {
2661                                                 return true;
2662                                         }
2663                                 }
2664                         }) );
2665                 }
2666
2667                 for ( i = 0; i < len; i++ ) {
2668                         jQuery.find( selector, self[ i ], ret );
2669                 }
2670
2671                 // Needed because $( selector, context ) becomes $( context ).find( selector )
2672                 ret = this.pushStack( len > 1 ? jQuery.unique( ret ) : ret );
2673                 ret.selector = this.selector ? this.selector + " " + selector : selector;
2674                 return ret;
2675         },
2676         filter: function( selector ) {
2677                 return this.pushStack( winnow(this, selector || [], false) );
2678         },
2679         not: function( selector ) {
2680                 return this.pushStack( winnow(this, selector || [], true) );
2681         },
2682         is: function( selector ) {
2683                 return !!winnow(
2684                         this,
2685
2686                         // If this is a positional/relative selector, check membership in the returned set
2687                         // so $("p:first").is("p:last") won't return true for a doc with two "p".
2688                         typeof selector === "string" && rneedsContext.test( selector ) ?
2689                                 jQuery( selector ) :
2690                                 selector || [],
2691                         false
2692                 ).length;
2693         }
2694 });
2695
2696
2697 // Initialize a jQuery object
2698
2699
2700 // A central reference to the root jQuery(document)
2701 var rootjQuery,
2702
2703         // A simple way to check for HTML strings
2704         // Prioritize #id over <tag> to avoid XSS via location.hash (#9521)
2705         // Strict HTML recognition (#11290: must start with <)
2706         rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,
2707
2708         init = jQuery.fn.init = function( selector, context ) {
2709                 var match, elem;
2710
2711                 // HANDLE: $(""), $(null), $(undefined), $(false)
2712                 if ( !selector ) {
2713                         return this;
2714                 }
2715
2716                 // Handle HTML strings
2717                 if ( typeof selector === "string" ) {
2718                         if ( selector[0] === "<" && selector[ selector.length - 1 ] === ">" && selector.length >= 3 ) {
2719                                 // Assume that strings that start and end with <> are HTML and skip the regex check
2720                                 match = [ null, selector, null ];
2721
2722                         } else {
2723                                 match = rquickExpr.exec( selector );
2724                         }
2725
2726                         // Match html or make sure no context is specified for #id
2727                         if ( match && (match[1] || !context) ) {
2728
2729                                 // HANDLE: $(html) -> $(array)
2730                                 if ( match[1] ) {
2731                                         context = context instanceof jQuery ? context[0] : context;
2732
2733                                         // scripts is true for back-compat
2734                                         // Intentionally let the error be thrown if parseHTML is not present
2735                                         jQuery.merge( this, jQuery.parseHTML(
2736                                                 match[1],
2737                                                 context && context.nodeType ? context.ownerDocument || context : document,
2738                                                 true
2739                                         ) );
2740
2741                                         // HANDLE: $(html, props)
2742                                         if ( rsingleTag.test( match[1] ) && jQuery.isPlainObject( context ) ) {
2743                                                 for ( match in context ) {
2744                                                         // Properties of context are called as methods if possible
2745                                                         if ( jQuery.isFunction( this[ match ] ) ) {
2746                                                                 this[ match ]( context[ match ] );
2747
2748                                                         // ...and otherwise set as attributes
2749                                                         } else {
2750                                                                 this.attr( match, context[ match ] );
2751                                                         }
2752                                                 }
2753                                         }
2754
2755                                         return this;
2756
2757                                 // HANDLE: $(#id)
2758                                 } else {
2759                                         elem = document.getElementById( match[2] );
2760
2761                                         // Check parentNode to catch when Blackberry 4.6 returns
2762                                         // nodes that are no longer in the document #6963
2763                                         if ( elem && elem.parentNode ) {
2764                                                 // Inject the element directly into the jQuery object
2765                                                 this.length = 1;
2766                                                 this[0] = elem;
2767                                         }
2768
2769                                         this.context = document;
2770                                         this.selector = selector;
2771                                         return this;
2772                                 }
2773
2774                         // HANDLE: $(expr, $(...))
2775                         } else if ( !context || context.jquery ) {
2776                                 return ( context || rootjQuery ).find( selector );
2777
2778                         // HANDLE: $(expr, context)
2779                         // (which is just equivalent to: $(context).find(expr)
2780                         } else {
2781                                 return this.constructor( context ).find( selector );
2782                         }
2783
2784                 // HANDLE: $(DOMElement)
2785                 } else if ( selector.nodeType ) {
2786                         this.context = this[0] = selector;
2787                         this.length = 1;
2788                         return this;
2789
2790                 // HANDLE: $(function)
2791                 // Shortcut for document ready
2792                 } else if ( jQuery.isFunction( selector ) ) {
2793                         return typeof rootjQuery.ready !== "undefined" ?
2794                                 rootjQuery.ready( selector ) :
2795                                 // Execute immediately if ready is not present
2796                                 selector( jQuery );
2797                 }
2798
2799                 if ( selector.selector !== undefined ) {
2800                         this.selector = selector.selector;
2801                         this.context = selector.context;
2802                 }
2803
2804                 return jQuery.makeArray( selector, this );
2805         };
2806
2807 // Give the init function the jQuery prototype for later instantiation
2808 init.prototype = jQuery.fn;
2809
2810 // Initialize central reference
2811 rootjQuery = jQuery( document );
2812
2813
2814 var rparentsprev = /^(?:parents|prev(?:Until|All))/,
2815         // methods guaranteed to produce a unique set when starting from a unique set
2816         guaranteedUnique = {
2817                 children: true,
2818                 contents: true,
2819                 next: true,
2820                 prev: true
2821         };
2822
2823 jQuery.extend({
2824         dir: function( elem, dir, until ) {
2825                 var matched = [],
2826                         truncate = until !== undefined;
2827
2828                 while ( (elem = elem[ dir ]) && elem.nodeType !== 9 ) {
2829                         if ( elem.nodeType === 1 ) {
2830                                 if ( truncate && jQuery( elem ).is( until ) ) {
2831                                         break;
2832                                 }
2833                                 matched.push( elem );
2834                         }
2835                 }
2836                 return matched;
2837         },
2838
2839         sibling: function( n, elem ) {
2840                 var matched = [];
2841
2842                 for ( ; n; n = n.nextSibling ) {
2843                         if ( n.nodeType === 1 && n !== elem ) {
2844                                 matched.push( n );
2845                         }
2846                 }
2847
2848                 return matched;
2849         }
2850 });
2851
2852 jQuery.fn.extend({
2853         has: function( target ) {
2854                 var targets = jQuery( target, this ),
2855                         l = targets.length;
2856
2857                 return this.filter(function() {
2858                         var i = 0;
2859                         for ( ; i < l; i++ ) {
2860                                 if ( jQuery.contains( this, targets[i] ) ) {
2861                                         return true;
2862                                 }
2863                         }
2864                 });
2865         },
2866
2867         closest: function( selectors, context ) {
2868                 var cur,
2869                         i = 0,
2870                         l = this.length,
2871                         matched = [],
2872                         pos = rneedsContext.test( selectors ) || typeof selectors !== "string" ?
2873                                 jQuery( selectors, context || this.context ) :
2874                                 0;
2875
2876                 for ( ; i < l; i++ ) {
2877                         for ( cur = this[i]; cur && cur !== context; cur = cur.parentNode ) {
2878                                 // Always skip document fragments
2879                                 if ( cur.nodeType < 11 && (pos ?
2880                                         pos.index(cur) > -1 :
2881
2882                                         // Don't pass non-elements to Sizzle
2883                                         cur.nodeType === 1 &&
2884                                                 jQuery.find.matchesSelector(cur, selectors)) ) {
2885
2886                                         matched.push( cur );
2887                                         break;
2888                                 }
2889                         }
2890                 }
2891
2892                 return this.pushStack( matched.length > 1 ? jQuery.unique( matched ) : matched );
2893         },
2894
2895         // Determine the position of an element within
2896         // the matched set of elements
2897         index: function( elem ) {
2898
2899                 // No argument, return index in parent
2900                 if ( !elem ) {
2901                         return ( this[ 0 ] && this[ 0 ].parentNode ) ? this.first().prevAll().length : -1;
2902                 }
2903
2904                 // index in selector
2905                 if ( typeof elem === "string" ) {
2906                         return indexOf.call( jQuery( elem ), this[ 0 ] );
2907                 }
2908
2909                 // Locate the position of the desired element
2910                 return indexOf.call( this,
2911
2912                         // If it receives a jQuery object, the first element is used
2913                         elem.jquery ? elem[ 0 ] : elem
2914                 );
2915         },
2916
2917         add: function( selector, context ) {
2918                 return this.pushStack(
2919                         jQuery.unique(
2920                                 jQuery.merge( this.get(), jQuery( selector, context ) )
2921                         )
2922                 );
2923         },
2924
2925         addBack: function( selector ) {
2926                 return this.add( selector == null ?
2927                         this.prevObject : this.prevObject.filter(selector)
2928                 );
2929         }
2930 });
2931
2932 function sibling( cur, dir ) {
2933         while ( (cur = cur[dir]) && cur.nodeType !== 1 ) {}
2934         return cur;
2935 }
2936
2937 jQuery.each({
2938         parent: function( elem ) {
2939                 var parent = elem.parentNode;
2940                 return parent && parent.nodeType !== 11 ? parent : null;
2941         },
2942         parents: function( elem ) {
2943                 return jQuery.dir( elem, "parentNode" );
2944         },
2945         parentsUntil: function( elem, i, until ) {
2946                 return jQuery.dir( elem, "parentNode", until );
2947         },
2948         next: function( elem ) {
2949                 return sibling( elem, "nextSibling" );
2950         },
2951         prev: function( elem ) {
2952                 return sibling( elem, "previousSibling" );
2953         },
2954         nextAll: function( elem ) {
2955                 return jQuery.dir( elem, "nextSibling" );
2956         },
2957         prevAll: function( elem ) {
2958                 return jQuery.dir( elem, "previousSibling" );
2959         },
2960         nextUntil: function( elem, i, until ) {
2961                 return jQuery.dir( elem, "nextSibling", until );
2962         },
2963         prevUntil: function( elem, i, until ) {
2964                 return jQuery.dir( elem, "previousSibling", until );
2965         },
2966         siblings: function( elem ) {
2967                 return jQuery.sibling( ( elem.parentNode || {} ).firstChild, elem );
2968         },
2969         children: function( elem ) {
2970                 return jQuery.sibling( elem.firstChild );
2971         },
2972         contents: function( elem ) {
2973                 return elem.contentDocument || jQuery.merge( [], elem.childNodes );
2974         }
2975 }, function( name, fn ) {
2976         jQuery.fn[ name ] = function( until, selector ) {
2977                 var matched = jQuery.map( this, fn, until );
2978
2979                 if ( name.slice( -5 ) !== "Until" ) {
2980                         selector = until;
2981                 }
2982
2983                 if ( selector && typeof selector === "string" ) {
2984                         matched = jQuery.filter( selector, matched );
2985                 }
2986
2987                 if ( this.length > 1 ) {
2988                         // Remove duplicates
2989                         if ( !guaranteedUnique[ name ] ) {
2990                                 jQuery.unique( matched );
2991                         }
2992
2993                         // Reverse order for parents* and prev-derivatives
2994                         if ( rparentsprev.test( name ) ) {
2995                                 matched.reverse();
2996                         }
2997                 }
2998
2999                 return this.pushStack( matched );
3000         };
3001 });
3002 var rnotwhite = (/\S+/g);
3003
3004
3005
3006 // String to Object options format cache
3007 var optionsCache = {};
3008
3009 // Convert String-formatted options into Object-formatted ones and store in cache
3010 function createOptions( options ) {
3011         var object = optionsCache[ options ] = {};
3012         jQuery.each( options.match( rnotwhite ) || [], function( _, flag ) {
3013                 object[ flag ] = true;
3014         });
3015         return object;
3016 }
3017
3018 /*
3019  * Create a callback list using the following parameters:
3020  *
3021  *      options: an optional list of space-separated options that will change how
3022  *                      the callback list behaves or a more traditional option object
3023  *
3024  * By default a callback list will act like an event callback list and can be
3025  * "fired" multiple times.
3026  *
3027  * Possible options:
3028  *
3029  *      once:                   will ensure the callback list can only be fired once (like a Deferred)
3030  *
3031  *      memory:                 will keep track of previous values and will call any callback added
3032  *                                      after the list has been fired right away with the latest "memorized"
3033  *                                      values (like a Deferred)
3034  *
3035  *      unique:                 will ensure a callback can only be added once (no duplicate in the list)
3036  *
3037  *      stopOnFalse:    interrupt callings when a callback returns false
3038  *
3039  */
3040 jQuery.Callbacks = function( options ) {
3041
3042         // Convert options from String-formatted to Object-formatted if needed
3043         // (we check in cache first)
3044         options = typeof options === "string" ?
3045                 ( optionsCache[ options ] || createOptions( options ) ) :
3046                 jQuery.extend( {}, options );
3047
3048         var // Last fire value (for non-forgettable lists)
3049                 memory,
3050                 // Flag to know if list was already fired
3051                 fired,
3052                 // Flag to know if list is currently firing
3053                 firing,
3054                 // First callback to fire (used internally by add and fireWith)
3055                 firingStart,
3056                 // End of the loop when firing
3057                 firingLength,
3058                 // Index of currently firing callback (modified by remove if needed)
3059                 firingIndex,
3060                 // Actual callback list
3061                 list = [],
3062                 // Stack of fire calls for repeatable lists
3063                 stack = !options.once && [],
3064                 // Fire callbacks
3065                 fire = function( data ) {
3066                         memory = options.memory && data;
3067                         fired = true;
3068                         firingIndex = firingStart || 0;
3069                         firingStart = 0;
3070                         firingLength = list.length;
3071                         firing = true;
3072                         for ( ; list && firingIndex < firingLength; firingIndex++ ) {
3073                                 if ( list[ firingIndex ].apply( data[ 0 ], data[ 1 ] ) === false && options.stopOnFalse ) {
3074                                         memory = false; // To prevent further calls using add
3075                                         break;
3076                                 }
3077                         }
3078                         firing = false;
3079                         if ( list ) {
3080                                 if ( stack ) {
3081                                         if ( stack.length ) {
3082                                                 fire( stack.shift() );
3083                                         }
3084                                 } else if ( memory ) {
3085                                         list = [];
3086                                 } else {
3087                                         self.disable();
3088                                 }
3089                         }
3090                 },
3091                 // Actual Callbacks object
3092                 self = {
3093                         // Add a callback or a collection of callbacks to the list
3094                         add: function() {
3095                                 if ( list ) {
3096                                         // First, we save the current length
3097                                         var start = list.length;
3098                                         (function add( args ) {
3099                                                 jQuery.each( args, function( _, arg ) {
3100                                                         var type = jQuery.type( arg );
3101                                                         if ( type === "function" ) {
3102                                                                 if ( !options.unique || !self.has( arg ) ) {
3103                                                                         list.push( arg );
3104                                                                 }
3105                                                         } else if ( arg && arg.length && type !== "string" ) {
3106                                                                 // Inspect recursively
3107                                                                 add( arg );
3108                                                         }
3109                                                 });
3110                                         })( arguments );
3111                                         // Do we need to add the callbacks to the
3112                                         // current firing batch?
3113                                         if ( firing ) {
3114                                                 firingLength = list.length;
3115                                         // With memory, if we're not firing then
3116                                         // we should call right away
3117                                         } else if ( memory ) {
3118                                                 firingStart = start;
3119                                                 fire( memory );
3120                                         }
3121                                 }
3122                                 return this;
3123                         },
3124                         // Remove a callback from the list
3125                         remove: function() {
3126                                 if ( list ) {
3127                                         jQuery.each( arguments, function( _, arg ) {
3128                                                 var index;
3129                                                 while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) {
3130                                                         list.splice( index, 1 );
3131                                                         // Handle firing indexes
3132                                                         if ( firing ) {
3133                                                                 if ( index <= firingLength ) {
3134                                                                         firingLength--;
3135                                                                 }
3136                                                                 if ( index <= firingIndex ) {
3137                                                                         firingIndex--;
3138                                                                 }
3139                                                         }
3140                                                 }
3141                                         });
3142                                 }
3143                                 return this;
3144                         },
3145                         // Check if a given callback is in the list.
3146                         // If no argument is given, return whether or not list has callbacks attached.
3147                         has: function( fn ) {
3148                                 return fn ? jQuery.inArray( fn, list ) > -1 : !!( list && list.length );
3149                         },
3150                         // Remove all callbacks from the list
3151                         empty: function() {
3152                                 list = [];
3153                                 firingLength = 0;
3154                                 return this;
3155                         },
3156                         // Have the list do nothing anymore
3157                         disable: function() {
3158                                 list = stack = memory = undefined;
3159                                 return this;
3160                         },
3161                         // Is it disabled?
3162                         disabled: function() {
3163                                 return !list;
3164                         },
3165                         // Lock the list in its current state
3166                         lock: function() {
3167                                 stack = undefined;
3168                                 if ( !memory ) {
3169                                         self.disable();
3170                                 }
3171                                 return this;
3172                         },
3173                         // Is it locked?
3174                         locked: function() {
3175                                 return !stack;
3176                         },
3177                         // Call all callbacks with the given context and arguments
3178                         fireWith: function( context, args ) {
3179                                 if ( list && ( !fired || stack ) ) {
3180                                         args = args || [];
3181                                         args = [ context, args.slice ? args.slice() : args ];
3182                                         if ( firing ) {
3183                                                 stack.push( args );
3184                                         } else {
3185                                                 fire( args );
3186                                         }
3187                                 }
3188                                 return this;
3189                         },
3190                         // Call all the callbacks with the given arguments
3191                         fire: function() {
3192                                 self.fireWith( this, arguments );
3193                                 return this;
3194                         },
3195                         // To know if the callbacks have already been called at least once
3196                         fired: function() {
3197                                 return !!fired;
3198                         }
3199                 };
3200
3201         return self;
3202 };
3203
3204
3205 jQuery.extend({
3206
3207         Deferred: function( func ) {
3208                 var tuples = [
3209                                 // action, add listener, listener list, final state
3210                                 [ "resolve", "done", jQuery.Callbacks("once memory"), "resolved" ],
3211                                 [ "reject", "fail", jQuery.Callbacks("once memory"), "rejected" ],
3212                                 [ "notify", "progress", jQuery.Callbacks("memory") ]
3213                         ],
3214                         state = "pending",
3215                         promise = {
3216                                 state: function() {
3217                                         return state;
3218                                 },
3219                                 always: function() {
3220                                         deferred.done( arguments ).fail( arguments );
3221                                         return this;
3222                                 },
3223                                 then: function( /* fnDone, fnFail, fnProgress */ ) {
3224                                         var fns = arguments;
3225                                         return jQuery.Deferred(function( newDefer ) {
3226                                                 jQuery.each( tuples, function( i, tuple ) {
3227                                                         var fn = jQuery.isFunction( fns[ i ] ) && fns[ i ];
3228                                                         // deferred[ done | fail | progress ] for forwarding actions to newDefer
3229                                                         deferred[ tuple[1] ](function() {
3230                                                                 var returned = fn && fn.apply( this, arguments );
3231                                                                 if ( returned && jQuery.isFunction( returned.promise ) ) {
3232                                                                         returned.promise()
3233                                                                                 .done( newDefer.resolve )
3234                                                                                 .fail( newDefer.reject )
3235                                                                                 .progress( newDefer.notify );
3236                                                                 } else {
3237                                                                         newDefer[ tuple[ 0 ] + "With" ]( this === promise ? newDefer.promise() : this, fn ? [ returned ] : arguments );
3238                                                                 }
3239                                                         });
3240                                                 });
3241                                                 fns = null;
3242                                         }).promise();
3243                                 },
3244                                 // Get a promise for this deferred
3245                                 // If obj is provided, the promise aspect is added to the object
3246                                 promise: function( obj ) {
3247                                         return obj != null ? jQuery.extend( obj, promise ) : promise;
3248                                 }
3249                         },
3250                         deferred = {};
3251
3252                 // Keep pipe for back-compat
3253                 promise.pipe = promise.then;
3254
3255                 // Add list-specific methods
3256                 jQuery.each( tuples, function( i, tuple ) {
3257                         var list = tuple[ 2 ],
3258                                 stateString = tuple[ 3 ];
3259
3260                         // promise[ done | fail | progress ] = list.add
3261                         promise[ tuple[1] ] = list.add;
3262
3263                         // Handle state
3264                         if ( stateString ) {
3265                                 list.add(function() {
3266                                         // state = [ resolved | rejected ]
3267                                         state = stateString;
3268
3269                                 // [ reject_list | resolve_list ].disable; progress_list.lock
3270                                 }, tuples[ i ^ 1 ][ 2 ].disable, tuples[ 2 ][ 2 ].lock );
3271                         }
3272
3273                         // deferred[ resolve | reject | notify ]
3274                         deferred[ tuple[0] ] = function() {
3275                                 deferred[ tuple[0] + "With" ]( this === deferred ? promise : this, arguments );
3276                                 return this;
3277                         };
3278                         deferred[ tuple[0] + "With" ] = list.fireWith;
3279                 });
3280
3281                 // Make the deferred a promise
3282                 promise.promise( deferred );
3283
3284                 // Call given func if any
3285                 if ( func ) {
3286                         func.call( deferred, deferred );
3287                 }
3288
3289                 // All done!
3290                 return deferred;
3291         },
3292
3293         // Deferred helper
3294         when: function( subordinate /* , ..., subordinateN */ ) {
3295                 var i = 0,
3296                         resolveValues = slice.call( arguments ),
3297                         length = resolveValues.length,
3298
3299                         // the count of uncompleted subordinates
3300                         remaining = length !== 1 || ( subordinate && jQuery.isFunction( subordinate.promise ) ) ? length : 0,
3301
3302                         // the master Deferred. If resolveValues consist of only a single Deferred, just use that.
3303                         deferred = remaining === 1 ? subordinate : jQuery.Deferred(),
3304
3305                         // Update function for both resolve and progress values
3306                         updateFunc = function( i, contexts, values ) {
3307                                 return function( value ) {
3308                                         contexts[ i ] = this;
3309                                         values[ i ] = arguments.length > 1 ? slice.call( arguments ) : value;
3310                                         if ( values === progressValues ) {
3311                                                 deferred.notifyWith( contexts, values );
3312                                         } else if ( !( --remaining ) ) {
3313                                                 deferred.resolveWith( contexts, values );
3314                                         }
3315                                 };
3316                         },
3317
3318                         progressValues, progressContexts, resolveContexts;
3319
3320                 // add listeners to Deferred subordinates; treat others as resolved
3321                 if ( length > 1 ) {
3322                         progressValues = new Array( length );
3323                         progressContexts = new Array( length );
3324                         resolveContexts = new Array( length );
3325                         for ( ; i < length; i++ ) {
3326                                 if ( resolveValues[ i ] && jQuery.isFunction( resolveValues[ i ].promise ) ) {
3327                                         resolveValues[ i ].promise()
3328                                                 .done( updateFunc( i, resolveContexts, resolveValues ) )
3329                                                 .fail( deferred.reject )
3330                                                 .progress( updateFunc( i, progressContexts, progressValues ) );
3331                                 } else {
3332                                         --remaining;
3333                                 }
3334                         }
3335                 }
3336
3337                 // if we're not waiting on anything, resolve the master
3338                 if ( !remaining ) {
3339                         deferred.resolveWith( resolveContexts, resolveValues );
3340                 }
3341
3342                 return deferred.promise();
3343         }
3344 });
3345
3346
3347 // The deferred used on DOM ready
3348 var readyList;
3349
3350 jQuery.fn.ready = function( fn ) {
3351         // Add the callback
3352         jQuery.ready.promise().done( fn );
3353
3354         return this;
3355 };
3356
3357 jQuery.extend({
3358         // Is the DOM ready to be used? Set to true once it occurs.
3359         isReady: false,
3360
3361         // A counter to track how many items to wait for before
3362         // the ready event fires. See #6781
3363         readyWait: 1,
3364
3365         // Hold (or release) the ready event
3366         holdReady: function( hold ) {
3367                 if ( hold ) {
3368                         jQuery.readyWait++;
3369                 } else {
3370                         jQuery.ready( true );
3371                 }
3372         },
3373
3374         // Handle when the DOM is ready
3375         ready: function( wait ) {
3376
3377                 // Abort if there are pending holds or we're already ready
3378                 if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) {
3379                         return;
3380                 }
3381
3382                 // Remember that the DOM is ready
3383                 jQuery.isReady = true;
3384
3385                 // If a normal DOM Ready event fired, decrement, and wait if need be
3386                 if ( wait !== true && --jQuery.readyWait > 0 ) {
3387                         return;
3388                 }
3389
3390                 // If there are functions bound, to execute
3391                 readyList.resolveWith( document, [ jQuery ] );
3392
3393                 // Trigger any bound ready events
3394                 if ( jQuery.fn.triggerHandler ) {
3395                         jQuery( document ).triggerHandler( "ready" );
3396                         jQuery( document ).off( "ready" );
3397                 }
3398         }
3399 });
3400
3401 /**
3402  * The ready event handler and self cleanup method
3403  */
3404 function completed() {
3405         document.removeEventListener( "DOMContentLoaded", completed, false );
3406         window.removeEventListener( "load", completed, false );
3407         jQuery.ready();
3408 }
3409
3410 jQuery.ready.promise = function( obj ) {
3411         if ( !readyList ) {
3412
3413                 readyList = jQuery.Deferred();
3414
3415                 // Catch cases where $(document).ready() is called after the browser event has already occurred.
3416                 // we once tried to use readyState "interactive" here, but it caused issues like the one
3417                 // discovered by ChrisS here: http://bugs.jquery.com/ticket/12282#comment:15
3418                 if ( document.readyState === "complete" ) {
3419                         // Handle it asynchronously to allow scripts the opportunity to delay ready
3420                         setTimeout( jQuery.ready );
3421
3422                 } else {
3423
3424                         // Use the handy event callback
3425                         document.addEventListener( "DOMContentLoaded", completed, false );
3426
3427                         // A fallback to window.onload, that will always work
3428                         window.addEventListener( "load", completed, false );
3429                 }
3430         }
3431         return readyList.promise( obj );
3432 };
3433
3434 // Kick off the DOM ready check even if the user does not
3435 jQuery.ready.promise();
3436
3437
3438
3439
3440 // Multifunctional method to get and set values of a collection
3441 // The value/s can optionally be executed if it's a function
3442 var access = jQuery.access = function( elems, fn, key, value, chainable, emptyGet, raw ) {
3443         var i = 0,
3444                 len = elems.length,
3445                 bulk = key == null;
3446
3447         // Sets many values
3448         if ( jQuery.type( key ) === "object" ) {
3449                 chainable = true;
3450                 for ( i in key ) {
3451                         jQuery.access( elems, fn, i, key[i], true, emptyGet, raw );
3452                 }
3453
3454         // Sets one value
3455         } else if ( value !== undefined ) {
3456                 chainable = true;
3457
3458                 if ( !jQuery.isFunction( value ) ) {
3459                         raw = true;
3460                 }
3461
3462                 if ( bulk ) {
3463                         // Bulk operations run against the entire set
3464                         if ( raw ) {
3465                                 fn.call( elems, value );
3466                                 fn = null;
3467
3468                         // ...except when executing function values
3469                         } else {
3470                                 bulk = fn;
3471                                 fn = function( elem, key, value ) {
3472                                         return bulk.call( jQuery( elem ), value );
3473                                 };
3474                         }
3475                 }
3476
3477                 if ( fn ) {
3478                         for ( ; i < len; i++ ) {
3479                                 fn( elems[i], key, raw ? value : value.call( elems[i], i, fn( elems[i], key ) ) );
3480                         }
3481                 }
3482         }
3483
3484         return chainable ?
3485                 elems :
3486
3487                 // Gets
3488                 bulk ?
3489                         fn.call( elems ) :
3490                         len ? fn( elems[0], key ) : emptyGet;
3491 };
3492
3493
3494 /**
3495  * Determines whether an object can have data
3496  */
3497 jQuery.acceptData = function( owner ) {
3498         // Accepts only:
3499         //  - Node
3500         //    - Node.ELEMENT_NODE
3501         //    - Node.DOCUMENT_NODE
3502         //  - Object
3503         //    - Any
3504         /* jshint -W018 */
3505         return owner.nodeType === 1 || owner.nodeType === 9 || !( +owner.nodeType );
3506 };
3507
3508
3509 function Data() {
3510         // Support: Android < 4,
3511         // Old WebKit does not have Object.preventExtensions/freeze method,
3512         // return new empty object instead with no [[set]] accessor
3513         Object.defineProperty( this.cache = {}, 0, {
3514                 get: function() {
3515                         return {};
3516                 }
3517         });
3518
3519         this.expando = jQuery.expando + Math.random();
3520 }
3521
3522 Data.uid = 1;
3523 Data.accepts = jQuery.acceptData;
3524
3525 Data.prototype = {
3526         key: function( owner ) {
3527                 // We can accept data for non-element nodes in modern browsers,
3528                 // but we should not, see #8335.
3529                 // Always return the key for a frozen object.
3530                 if ( !Data.accepts( owner ) ) {
3531                         return 0;
3532                 }
3533
3534                 var descriptor = {},
3535                         // Check if the owner object already has a cache key
3536                         unlock = owner[ this.expando ];
3537
3538                 // If not, create one
3539                 if ( !unlock ) {
3540                         unlock = Data.uid++;
3541
3542                         // Secure it in a non-enumerable, non-writable property
3543                         try {
3544                                 descriptor[ this.expando ] = { value: unlock };
3545                                 Object.defineProperties( owner, descriptor );
3546
3547                         // Support: Android < 4
3548                         // Fallback to a less secure definition
3549                         } catch ( e ) {
3550                                 descriptor[ this.expando ] = unlock;
3551                                 jQuery.extend( owner, descriptor );
3552                         }
3553                 }
3554
3555                 // Ensure the cache object
3556                 if ( !this.cache[ unlock ] ) {
3557                         this.cache[ unlock ] = {};
3558                 }
3559
3560                 return unlock;
3561         },
3562         set: function( owner, data, value ) {
3563                 var prop,
3564                         // There may be an unlock assigned to this node,
3565                         // if there is no entry for this "owner", create one inline
3566                         // and set the unlock as though an owner entry had always existed
3567                         unlock = this.key( owner ),
3568                         cache = this.cache[ unlock ];
3569
3570                 // Handle: [ owner, key, value ] args
3571                 if ( typeof data === "string" ) {
3572                         cache[ data ] = value;
3573
3574                 // Handle: [ owner, { properties } ] args
3575                 } else {
3576                         // Fresh assignments by object are shallow copied
3577                         if ( jQuery.isEmptyObject( cache ) ) {
3578                                 jQuery.extend( this.cache[ unlock ], data );
3579                         // Otherwise, copy the properties one-by-one to the cache object
3580                         } else {
3581                                 for ( prop in data ) {
3582                                         cache[ prop ] = data[ prop ];
3583                                 }
3584                         }
3585                 }
3586                 return cache;
3587         },
3588         get: function( owner, key ) {
3589                 // Either a valid cache is found, or will be created.
3590                 // New caches will be created and the unlock returned,
3591                 // allowing direct access to the newly created
3592                 // empty data object. A valid owner object must be provided.
3593                 var cache = this.cache[ this.key( owner ) ];
3594
3595                 return key === undefined ?
3596                         cache : cache[ key ];
3597         },
3598         access: function( owner, key, value ) {
3599                 var stored;
3600                 // In cases where either:
3601                 //
3602                 //   1. No key was specified
3603                 //   2. A string key was specified, but no value provided
3604                 //
3605                 // Take the "read" path and allow the get method to determine
3606                 // which value to return, respectively either:
3607                 //
3608                 //   1. The entire cache object
3609                 //   2. The data stored at the key
3610                 //
3611                 if ( key === undefined ||
3612                                 ((key && typeof key === "string") && value === undefined) ) {
3613
3614                         stored = this.get( owner, key );
3615
3616                         return stored !== undefined ?
3617                                 stored : this.get( owner, jQuery.camelCase(key) );
3618                 }
3619
3620                 // [*]When the key is not a string, or both a key and value
3621                 // are specified, set or extend (existing objects) with either:
3622                 //
3623                 //   1. An object of properties
3624                 //   2. A key and value
3625                 //
3626                 this.set( owner, key, value );
3627
3628                 // Since the "set" path can have two possible entry points
3629                 // return the expected data based on which path was taken[*]
3630                 return value !== undefined ? value : key;
3631         },
3632         remove: function( owner, key ) {
3633                 var i, name, camel,
3634                         unlock = this.key( owner ),
3635                         cache = this.cache[ unlock ];
3636
3637                 if ( key === undefined ) {
3638                         this.cache[ unlock ] = {};
3639
3640                 } else {
3641                         // Support array or space separated string of keys
3642                         if ( jQuery.isArray( key ) ) {
3643                                 // If "name" is an array of keys...
3644                                 // When data is initially created, via ("key", "val") signature,
3645                                 // keys will be converted to camelCase.
3646                                 // Since there is no way to tell _how_ a key was added, remove
3647                                 // both plain key and camelCase key. #12786
3648                                 // This will only penalize the array argument path.
3649                                 name = key.concat( key.map( jQuery.camelCase ) );
3650                         } else {
3651                                 camel = jQuery.camelCase( key );
3652                                 // Try the string as a key before any manipulation
3653                                 if ( key in cache ) {
3654                                         name = [ key, camel ];
3655                                 } else {
3656                                         // If a key with the spaces exists, use it.
3657                                         // Otherwise, create an array by matching non-whitespace
3658                                         name = camel;
3659                                         name = name in cache ?
3660                                                 [ name ] : ( name.match( rnotwhite ) || [] );
3661                                 }
3662                         }
3663
3664                         i = name.length;
3665                         while ( i-- ) {
3666                                 delete cache[ name[ i ] ];
3667                         }
3668                 }
3669         },
3670         hasData: function( owner ) {
3671                 return !jQuery.isEmptyObject(
3672                         this.cache[ owner[ this.expando ] ] || {}
3673                 );
3674         },
3675         discard: function( owner ) {
3676                 if ( owner[ this.expando ] ) {
3677                         delete this.cache[ owner[ this.expando ] ];
3678                 }
3679         }
3680 };
3681 var data_priv = new Data();
3682
3683 var data_user = new Data();
3684
3685
3686
3687 /*
3688         Implementation Summary
3689
3690         1. Enforce API surface and semantic compatibility with 1.9.x branch
3691         2. Improve the module's maintainability by reducing the storage
3692                 paths to a single mechanism.
3693         3. Use the same single mechanism to support "private" and "user" data.
3694         4. _Never_ expose "private" data to user code (TODO: Drop _data, _removeData)
3695         5. Avoid exposing implementation details on user objects (eg. expando properties)
3696         6. Provide a clear path for implementation upgrade to WeakMap in 2014
3697 */
3698 var rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,
3699         rmultiDash = /([A-Z])/g;
3700
3701 function dataAttr( elem, key, data ) {
3702         var name;
3703
3704         // If nothing was found internally, try to fetch any
3705         // data from the HTML5 data-* attribute
3706         if ( data === undefined && elem.nodeType === 1 ) {
3707                 name = "data-" + key.replace( rmultiDash, "-$1" ).toLowerCase();
3708                 data = elem.getAttribute( name );
3709
3710                 if ( typeof data === "string" ) {
3711                         try {
3712                                 data = data === "true" ? true :
3713                                         data === "false" ? false :
3714                                         data === "null" ? null :
3715                                         // Only convert to a number if it doesn't change the string
3716                                         +data + "" === data ? +data :
3717                                         rbrace.test( data ) ? jQuery.parseJSON( data ) :
3718                                         data;
3719                         } catch( e ) {}
3720
3721                         // Make sure we set the data so it isn't changed later
3722                         data_user.set( elem, key, data );
3723                 } else {
3724                         data = undefined;
3725                 }
3726         }
3727         return data;
3728 }
3729
3730 jQuery.extend({
3731         hasData: function( elem ) {
3732                 return data_user.hasData( elem ) || data_priv.hasData( elem );
3733         },
3734
3735         data: function( elem, name, data ) {
3736                 return data_user.access( elem, name, data );
3737         },
3738
3739         removeData: function( elem, name ) {
3740                 data_user.remove( elem, name );
3741         },
3742
3743         // TODO: Now that all calls to _data and _removeData have been replaced
3744         // with direct calls to data_priv methods, these can be deprecated.
3745         _data: function( elem, name, data ) {
3746                 return data_priv.access( elem, name, data );
3747         },
3748
3749         _removeData: function( elem, name ) {
3750                 data_priv.remove( elem, name );
3751         }
3752 });
3753
3754 jQuery.fn.extend({
3755         data: function( key, value ) {
3756                 var i, name, data,
3757                         elem = this[ 0 ],
3758                         attrs = elem && elem.attributes;
3759
3760                 // Gets all values
3761                 if ( key === undefined ) {
3762                         if ( this.length ) {
3763                                 data = data_user.get( elem );
3764
3765                                 if ( elem.nodeType === 1 && !data_priv.get( elem, "hasDataAttrs" ) ) {
3766                                         i = attrs.length;
3767                                         while ( i-- ) {
3768
3769                                                 // Support: IE11+
3770                                                 // The attrs elements can be null (#14894)
3771                                                 if ( attrs[ i ] ) {
3772                                                         name = attrs[ i ].name;
3773                                                         if ( name.indexOf( "data-" ) === 0 ) {
3774                                                                 name = jQuery.camelCase( name.slice(5) );
3775                                                                 dataAttr( elem, name, data[ name ] );
3776                                                         }
3777                                                 }
3778                                         }
3779                                         data_priv.set( elem, "hasDataAttrs", true );
3780                                 }
3781                         }
3782
3783                         return data;
3784                 }
3785
3786                 // Sets multiple values
3787                 if ( typeof key === "object" ) {
3788                         return this.each(function() {
3789                                 data_user.set( this, key );
3790                         });
3791                 }
3792
3793                 return access( this, function( value ) {
3794                         var data,
3795                                 camelKey = jQuery.camelCase( key );
3796
3797                         // The calling jQuery object (element matches) is not empty
3798                         // (and therefore has an element appears at this[ 0 ]) and the
3799                         // `value` parameter was not undefined. An empty jQuery object
3800                         // will result in `undefined` for elem = this[ 0 ] which will
3801                         // throw an exception if an attempt to read a data cache is made.
3802                         if ( elem && value === undefined ) {
3803                                 // Attempt to get data from the cache
3804                                 // with the key as-is
3805                                 data = data_user.get( elem, key );
3806                                 if ( data !== undefined ) {
3807                                         return data;
3808                                 }
3809
3810                                 // Attempt to get data from the cache
3811                                 // with the key camelized
3812                                 data = data_user.get( elem, camelKey );
3813                                 if ( data !== undefined ) {
3814                                         return data;
3815                                 }
3816
3817                                 // Attempt to "discover" the data in
3818                                 // HTML5 custom data-* attrs
3819                                 data = dataAttr( elem, camelKey, undefined );
3820                                 if ( data !== undefined ) {
3821                                         return data;
3822                                 }
3823
3824                                 // We tried really hard, but the data doesn't exist.
3825                                 return;
3826                         }
3827
3828                         // Set the data...
3829                         this.each(function() {
3830                                 // First, attempt to store a copy or reference of any
3831                                 // data that might've been store with a camelCased key.
3832                                 var data = data_user.get( this, camelKey );
3833
3834                                 // For HTML5 data-* attribute interop, we have to
3835                                 // store property names with dashes in a camelCase form.
3836                                 // This might not apply to all properties...*
3837                                 data_user.set( this, camelKey, value );
3838
3839                                 // *... In the case of properties that might _actually_
3840                                 // have dashes, we need to also store a copy of that
3841                                 // unchanged property.
3842                                 if ( key.indexOf("-") !== -1 && data !== undefined ) {
3843                                         data_user.set( this, key, value );
3844                                 }
3845                         });
3846                 }, null, value, arguments.length > 1, null, true );
3847         },
3848
3849         removeData: function( key ) {
3850                 return this.each(function() {
3851                         data_user.remove( this, key );
3852                 });
3853         }
3854 });
3855
3856
3857 jQuery.extend({
3858         queue: function( elem, type, data ) {
3859                 var queue;
3860
3861                 if ( elem ) {
3862                         type = ( type || "fx" ) + "queue";
3863                         queue = data_priv.get( elem, type );
3864
3865                         // Speed up dequeue by getting out quickly if this is just a lookup
3866                         if ( data ) {
3867                                 if ( !queue || jQuery.isArray( data ) ) {
3868                                         queue = data_priv.access( elem, type, jQuery.makeArray(data) );
3869                                 } else {
3870                                         queue.push( data );
3871                                 }
3872                         }
3873                         return queue || [];
3874                 }
3875         },
3876
3877         dequeue: function( elem, type ) {
3878                 type = type || "fx";
3879
3880                 var queue = jQuery.queue( elem, type ),
3881                         startLength = queue.length,
3882                         fn = queue.shift(),
3883                         hooks = jQuery._queueHooks( elem, type ),
3884                         next = function() {
3885                                 jQuery.dequeue( elem, type );
3886                         };
3887
3888                 // If the fx queue is dequeued, always remove the progress sentinel
3889                 if ( fn === "inprogress" ) {
3890                         fn = queue.shift();
3891                         startLength--;
3892                 }
3893
3894                 if ( fn ) {
3895
3896                         // Add a progress sentinel to prevent the fx queue from being
3897                         // automatically dequeued
3898                         if ( type === "fx" ) {
3899                                 queue.unshift( "inprogress" );
3900                         }
3901
3902                         // clear up the last queue stop function
3903                         delete hooks.stop;
3904                         fn.call( elem, next, hooks );
3905                 }
3906
3907                 if ( !startLength && hooks ) {
3908                         hooks.empty.fire();
3909                 }
3910         },
3911
3912         // not intended for public consumption - generates a queueHooks object, or returns the current one
3913         _queueHooks: function( elem, type ) {
3914                 var key = type + "queueHooks";
3915                 return data_priv.get( elem, key ) || data_priv.access( elem, key, {
3916                         empty: jQuery.Callbacks("once memory").add(function() {
3917                                 data_priv.remove( elem, [ type + "queue", key ] );
3918                         })
3919                 });
3920         }
3921 });
3922
3923 jQuery.fn.extend({
3924         queue: function( type, data ) {
3925                 var setter = 2;
3926
3927                 if ( typeof type !== "string" ) {
3928                         data = type;
3929                         type = "fx";
3930                         setter--;
3931                 }
3932
3933                 if ( arguments.length < setter ) {
3934                         return jQuery.queue( this[0], type );
3935                 }
3936
3937                 return data === undefined ?
3938                         this :
3939                         this.each(function() {
3940                                 var queue = jQuery.queue( this, type, data );
3941
3942                                 // ensure a hooks for this queue
3943                                 jQuery._queueHooks( this, type );
3944
3945                                 if ( type === "fx" && queue[0] !== "inprogress" ) {
3946                                         jQuery.dequeue( this, type );
3947                                 }
3948                         });
3949         },
3950         dequeue: function( type ) {
3951                 return this.each(function() {
3952                         jQuery.dequeue( this, type );
3953                 });
3954         },
3955         clearQueue: function( type ) {
3956                 return this.queue( type || "fx", [] );
3957         },
3958         // Get a promise resolved when queues of a certain type
3959         // are emptied (fx is the type by default)
3960         promise: function( type, obj ) {
3961                 var tmp,
3962                         count = 1,
3963                         defer = jQuery.Deferred(),
3964                         elements = this,
3965                         i = this.length,
3966                         resolve = function() {
3967                                 if ( !( --count ) ) {
3968                                         defer.resolveWith( elements, [ elements ] );
3969                                 }
3970                         };
3971
3972                 if ( typeof type !== "string" ) {
3973                         obj = type;
3974                         type = undefined;
3975                 }
3976                 type = type || "fx";
3977
3978                 while ( i-- ) {
3979                         tmp = data_priv.get( elements[ i ], type + "queueHooks" );
3980                         if ( tmp && tmp.empty ) {
3981                                 count++;
3982                                 tmp.empty.add( resolve );
3983                         }
3984                 }
3985                 resolve();
3986                 return defer.promise( obj );
3987         }
3988 });
3989 var pnum = (/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/).source;
3990
3991 var cssExpand = [ "Top", "Right", "Bottom", "Left" ];
3992
3993 var isHidden = function( elem, el ) {
3994                 // isHidden might be called from jQuery#filter function;
3995                 // in that case, element will be second argument
3996                 elem = el || elem;
3997                 return jQuery.css( elem, "display" ) === "none" || !jQuery.contains( elem.ownerDocument, elem );
3998         };
3999
4000 var rcheckableType = (/^(?:checkbox|radio)$/i);
4001
4002
4003
4004 (function() {
4005         var fragment = document.createDocumentFragment(),
4006                 div = fragment.appendChild( document.createElement( "div" ) ),
4007                 input = document.createElement( "input" );
4008
4009         // #11217 - WebKit loses check when the name is after the checked attribute
4010         // Support: Windows Web Apps (WWA)
4011         // `name` and `type` need .setAttribute for WWA
4012         input.setAttribute( "type", "radio" );
4013         input.setAttribute( "checked", "checked" );
4014         input.setAttribute( "name", "t" );
4015
4016         div.appendChild( input );
4017
4018         // Support: Safari 5.1, iOS 5.1, Android 4.x, Android 2.3
4019         // old WebKit doesn't clone checked state correctly in fragments
4020         support.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked;
4021
4022         // Make sure textarea (and checkbox) defaultValue is properly cloned
4023         // Support: IE9-IE11+
4024         div.innerHTML = "<textarea>x</textarea>";
4025         support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue;
4026 })();
4027 var strundefined = typeof undefined;
4028
4029
4030
4031 support.focusinBubbles = "onfocusin" in window;
4032
4033
4034 var
4035         rkeyEvent = /^key/,
4036         rmouseEvent = /^(?:mouse|pointer|contextmenu)|click/,
4037         rfocusMorph = /^(?:focusinfocus|focusoutblur)$/,
4038         rtypenamespace = /^([^.]*)(?:\.(.+)|)$/;
4039
4040 function returnTrue() {
4041         return true;
4042 }
4043
4044 function returnFalse() {
4045         return false;
4046 }
4047
4048 function safeActiveElement() {
4049         try {
4050                 return document.activeElement;
4051         } catch ( err ) { }
4052 }
4053
4054 /*
4055  * Helper functions for managing events -- not part of the public interface.
4056  * Props to Dean Edwards' addEvent library for many of the ideas.
4057  */
4058 jQuery.event = {
4059
4060         global: {},
4061
4062         add: function( elem, types, handler, data, selector ) {
4063
4064                 var handleObjIn, eventHandle, tmp,
4065                         events, t, handleObj,
4066                         special, handlers, type, namespaces, origType,
4067                         elemData = data_priv.get( elem );
4068
4069                 // Don't attach events to noData or text/comment nodes (but allow plain objects)
4070                 if ( !elemData ) {
4071                         return;
4072                 }
4073
4074                 // Caller can pass in an object of custom data in lieu of the handler
4075                 if ( handler.handler ) {
4076                         handleObjIn = handler;
4077                         handler = handleObjIn.handler;
4078                         selector = handleObjIn.selector;
4079                 }
4080
4081                 // Make sure that the handler has a unique ID, used to find/remove it later
4082                 if ( !handler.guid ) {
4083                         handler.guid = jQuery.guid++;
4084                 }
4085
4086                 // Init the element's event structure and main handler, if this is the first
4087                 if ( !(events = elemData.events) ) {
4088                         events = elemData.events = {};
4089                 }
4090                 if ( !(eventHandle = elemData.handle) ) {
4091                         eventHandle = elemData.handle = function( e ) {
4092                                 // Discard the second event of a jQuery.event.trigger() and
4093                                 // when an event is called after a page has unloaded
4094                                 return typeof jQuery !== strundefined && jQuery.event.triggered !== e.type ?
4095                                         jQuery.event.dispatch.apply( elem, arguments ) : undefined;
4096                         };
4097                 }
4098
4099                 // Handle multiple events separated by a space
4100                 types = ( types || "" ).match( rnotwhite ) || [ "" ];
4101                 t = types.length;
4102                 while ( t-- ) {
4103                         tmp = rtypenamespace.exec( types[t] ) || [];
4104                         type = origType = tmp[1];
4105                         namespaces = ( tmp[2] || "" ).split( "." ).sort();
4106
4107                         // There *must* be a type, no attaching namespace-only handlers
4108                         if ( !type ) {
4109                                 continue;
4110                         }
4111
4112                         // If event changes its type, use the special event handlers for the changed type
4113                         special = jQuery.event.special[ type ] || {};
4114
4115                         // If selector defined, determine special event api type, otherwise given type
4116                         type = ( selector ? special.delegateType : special.bindType ) || type;
4117
4118                         // Update special based on newly reset type
4119                         special = jQuery.event.special[ type ] || {};
4120
4121                         // handleObj is passed to all event handlers
4122                         handleObj = jQuery.extend({
4123                                 type: type,
4124                                 origType: origType,
4125                                 data: data,
4126                                 handler: handler,
4127                                 guid: handler.guid,
4128                                 selector: selector,
4129                                 needsContext: selector && jQuery.expr.match.needsContext.test( selector ),
4130                                 namespace: namespaces.join(".")
4131                         }, handleObjIn );
4132
4133                         // Init the event handler queue if we're the first
4134                         if ( !(handlers = events[ type ]) ) {
4135                                 handlers = events[ type ] = [];
4136                                 handlers.delegateCount = 0;
4137
4138                                 // Only use addEventListener if the special events handler returns false
4139                                 if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) {
4140                                         if ( elem.addEventListener ) {
4141                                                 elem.addEventListener( type, eventHandle, false );
4142                                         }
4143                                 }
4144                         }
4145
4146                         if ( special.add ) {
4147                                 special.add.call( elem, handleObj );
4148
4149                                 if ( !handleObj.handler.guid ) {
4150                                         handleObj.handler.guid = handler.guid;
4151                                 }
4152                         }
4153
4154                         // Add to the element's handler list, delegates in front
4155                         if ( selector ) {
4156                                 handlers.splice( handlers.delegateCount++, 0, handleObj );
4157                         } else {
4158                                 handlers.push( handleObj );
4159                         }
4160
4161                         // Keep track of which events have ever been used, for event optimization
4162                         jQuery.event.global[ type ] = true;
4163                 }
4164
4165         },
4166
4167         // Detach an event or set of events from an element
4168         remove: function( elem, types, handler, selector, mappedTypes ) {
4169
4170                 var j, origCount, tmp,
4171                         events, t, handleObj,
4172                         special, handlers, type, namespaces, origType,
4173                         elemData = data_priv.hasData( elem ) && data_priv.get( elem );
4174
4175                 if ( !elemData || !(events = elemData.events) ) {
4176                         return;
4177                 }
4178
4179                 // Once for each type.namespace in types; type may be omitted
4180                 types = ( types || "" ).match( rnotwhite ) || [ "" ];
4181                 t = types.length;
4182                 while ( t-- ) {
4183                         tmp = rtypenamespace.exec( types[t] ) || [];
4184                         type = origType = tmp[1];
4185                         namespaces = ( tmp[2] || "" ).split( "." ).sort();
4186
4187                         // Unbind all events (on this namespace, if provided) for the element
4188                         if ( !type ) {
4189                                 for ( type in events ) {
4190                                         jQuery.event.remove( elem, type + types[ t ], handler, selector, true );
4191                                 }
4192                                 continue;
4193                         }
4194
4195                         special = jQuery.event.special[ type ] || {};
4196                         type = ( selector ? special.delegateType : special.bindType ) || type;
4197                         handlers = events[ type ] || [];
4198                         tmp = tmp[2] && new RegExp( "(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)" );
4199
4200                         // Remove matching events
4201                         origCount = j = handlers.length;
4202                         while ( j-- ) {
4203                                 handleObj = handlers[ j ];
4204
4205                                 if ( ( mappedTypes || origType === handleObj.origType ) &&
4206                                         ( !handler || handler.guid === handleObj.guid ) &&
4207                                         ( !tmp || tmp.test( handleObj.namespace ) ) &&
4208                                         ( !selector || selector === handleObj.selector || selector === "**" && handleObj.selector ) ) {
4209                                         handlers.splice( j, 1 );
4210
4211                                         if ( handleObj.selector ) {
4212                                                 handlers.delegateCount--;
4213                                         }
4214                                         if ( special.remove ) {
4215                                                 special.remove.call( elem, handleObj );
4216                                         }
4217                                 }
4218                         }
4219
4220                         // Remove generic event handler if we removed something and no more handlers exist
4221                         // (avoids potential for endless recursion during removal of special event handlers)
4222                         if ( origCount && !handlers.length ) {
4223                                 if ( !special.teardown || special.teardown.call( elem, namespaces, elemData.handle ) === false ) {
4224                                         jQuery.removeEvent( elem, type, elemData.handle );
4225                                 }
4226
4227                                 delete events[ type ];
4228                         }
4229                 }
4230
4231                 // Remove the expando if it's no longer used
4232                 if ( jQuery.isEmptyObject( events ) ) {
4233                         delete elemData.handle;
4234                         data_priv.remove( elem, "events" );
4235                 }
4236         },
4237
4238         trigger: function( event, data, elem, onlyHandlers ) {
4239
4240                 var i, cur, tmp, bubbleType, ontype, handle, special,
4241                         eventPath = [ elem || document ],
4242                         type = hasOwn.call( event, "type" ) ? event.type : event,
4243                         namespaces = hasOwn.call( event, "namespace" ) ? event.namespace.split(".") : [];
4244
4245                 cur = tmp = elem = elem || document;
4246
4247                 // Don't do events on text and comment nodes
4248                 if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
4249                         return;
4250                 }
4251
4252                 // focus/blur morphs to focusin/out; ensure we're not firing them right now
4253                 if ( rfocusMorph.test( type + jQuery.event.triggered ) ) {
4254                         return;
4255                 }
4256
4257                 if ( type.indexOf(".") >= 0 ) {
4258                         // Namespaced trigger; create a regexp to match event type in handle()
4259                         namespaces = type.split(".");
4260                         type = namespaces.shift();
4261                         namespaces.sort();
4262                 }
4263                 ontype = type.indexOf(":") < 0 && "on" + type;
4264
4265                 // Caller can pass in a jQuery.Event object, Object, or just an event type string
4266                 event = event[ jQuery.expando ] ?
4267                         event :
4268                         new jQuery.Event( type, typeof event === "object" && event );
4269
4270                 // Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true)
4271                 event.isTrigger = onlyHandlers ? 2 : 3;
4272                 event.namespace = namespaces.join(".");
4273                 event.namespace_re = event.namespace ?
4274                         new RegExp( "(^|\\.)" + namespaces.join("\\.(?:.*\\.|)") + "(\\.|$)" ) :
4275                         null;
4276
4277                 // Clean up the event in case it is being reused
4278                 event.result = undefined;
4279                 if ( !event.target ) {
4280                         event.target = elem;
4281                 }
4282
4283                 // Clone any incoming data and prepend the event, creating the handler arg list
4284                 data = data == null ?
4285                         [ event ] :
4286                         jQuery.makeArray( data, [ event ] );
4287
4288                 // Allow special events to draw outside the lines
4289                 special = jQuery.event.special[ type ] || {};
4290                 if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) {
4291                         return;
4292                 }
4293
4294                 // Determine event propagation path in advance, per W3C events spec (#9951)
4295                 // Bubble up to document, then to window; watch for a global ownerDocument var (#9724)
4296                 if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) {
4297
4298                         bubbleType = special.delegateType || type;
4299                         if ( !rfocusMorph.test( bubbleType + type ) ) {
4300                                 cur = cur.parentNode;
4301                         }
4302                         for ( ; cur; cur = cur.parentNode ) {
4303                                 eventPath.push( cur );
4304                                 tmp = cur;
4305                         }
4306
4307                         // Only add window if we got to document (e.g., not plain obj or detached DOM)
4308                         if ( tmp === (elem.ownerDocument || document) ) {
4309                                 eventPath.push( tmp.defaultView || tmp.parentWindow || window );
4310                         }
4311                 }
4312
4313                 // Fire handlers on the event path
4314                 i = 0;
4315                 while ( (cur = eventPath[i++]) && !event.isPropagationStopped() ) {
4316
4317                         event.type = i > 1 ?
4318                                 bubbleType :
4319                                 special.bindType || type;
4320
4321                         // jQuery handler
4322                         handle = ( data_priv.get( cur, "events" ) || {} )[ event.type ] && data_priv.get( cur, "handle" );
4323                         if ( handle ) {
4324                                 handle.apply( cur, data );
4325                         }
4326
4327                         // Native handler
4328                         handle = ontype && cur[ ontype ];
4329                         if ( handle && handle.apply && jQuery.acceptData( cur ) ) {
4330                                 event.result = handle.apply( cur, data );
4331                                 if ( event.result === false ) {
4332                                         event.preventDefault();
4333                                 }
4334                         }
4335                 }
4336                 event.type = type;
4337
4338                 // If nobody prevented the default action, do it now
4339                 if ( !onlyHandlers && !event.isDefaultPrevented() ) {
4340
4341                         if ( (!special._default || special._default.apply( eventPath.pop(), data ) === false) &&
4342                                 jQuery.acceptData( elem ) ) {
4343
4344                                 // Call a native DOM method on the target with the same name name as the event.
4345                                 // Don't do default actions on window, that's where global variables be (#6170)
4346                                 if ( ontype && jQuery.isFunction( elem[ type ] ) && !jQuery.isWindow( elem ) ) {
4347
4348                                         // Don't re-trigger an onFOO event when we call its FOO() method
4349                                         tmp = elem[ ontype ];
4350
4351                                         if ( tmp ) {
4352                                                 elem[ ontype ] = null;
4353                                         }
4354
4355                                         // Prevent re-triggering of the same event, since we already bubbled it above
4356                                         jQuery.event.triggered = type;
4357                                         elem[ type ]();
4358                                         jQuery.event.triggered = undefined;
4359
4360                                         if ( tmp ) {
4361                                                 elem[ ontype ] = tmp;
4362                                         }
4363                                 }
4364                         }
4365                 }
4366
4367                 return event.result;
4368         },
4369
4370         dispatch: function( event ) {
4371
4372                 // Make a writable jQuery.Event from the native event object
4373                 event = jQuery.event.fix( event );
4374
4375                 var i, j, ret, matched, handleObj,
4376                         handlerQueue = [],
4377                         args = slice.call( arguments ),
4378                         handlers = ( data_priv.get( this, "events" ) || {} )[ event.type ] || [],
4379                         special = jQuery.event.special[ event.type ] || {};
4380
4381                 // Use the fix-ed jQuery.Event rather than the (read-only) native event
4382                 args[0] = event;
4383                 event.delegateTarget = this;
4384
4385                 // Call the preDispatch hook for the mapped type, and let it bail if desired
4386                 if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) {
4387                         return;
4388                 }
4389
4390                 // Determine handlers
4391                 handlerQueue = jQuery.event.handlers.call( this, event, handlers );
4392
4393                 // Run delegates first; they may want to stop propagation beneath us
4394                 i = 0;
4395                 while ( (matched = handlerQueue[ i++ ]) && !event.isPropagationStopped() ) {
4396                         event.currentTarget = matched.elem;
4397
4398                         j = 0;
4399                         while ( (handleObj = matched.handlers[ j++ ]) && !event.isImmediatePropagationStopped() ) {
4400
4401                                 // Triggered event must either 1) have no namespace, or
4402                                 // 2) have namespace(s) a subset or equal to those in the bound event (both can have no namespace).
4403                                 if ( !event.namespace_re || event.namespace_re.test( handleObj.namespace ) ) {
4404
4405                                         event.handleObj = handleObj;
4406                                         event.data = handleObj.data;
4407
4408                                         ret = ( (jQuery.event.special[ handleObj.origType ] || {}).handle || handleObj.handler )
4409                                                         .apply( matched.elem, args );
4410
4411                                         if ( ret !== undefined ) {
4412                                                 if ( (event.result = ret) === false ) {
4413                                                         event.preventDefault();
4414                                                         event.stopPropagation();
4415                                                 }
4416                                         }
4417                                 }
4418                         }
4419                 }
4420
4421                 // Call the postDispatch hook for the mapped type
4422                 if ( special.postDispatch ) {
4423                         special.postDispatch.call( this, event );
4424                 }
4425
4426                 return event.result;
4427         },
4428
4429         handlers: function( event, handlers ) {
4430                 var i, matches, sel, handleObj,
4431                         handlerQueue = [],
4432                         delegateCount = handlers.delegateCount,
4433                         cur = event.target;
4434
4435                 // Find delegate handlers
4436                 // Black-hole SVG <use> instance trees (#13180)
4437                 // Avoid non-left-click bubbling in Firefox (#3861)
4438                 if ( delegateCount && cur.nodeType && (!event.button || event.type !== "click") ) {
4439
4440                         for ( ; cur !== this; cur = cur.parentNode || this ) {
4441
4442                                 // Don't process clicks on disabled elements (#6911, #8165, #11382, #11764)
4443                                 if ( cur.disabled !== true || event.type !== "click" ) {
4444                                         matches = [];
4445                                         for ( i = 0; i < delegateCount; i++ ) {
4446                                                 handleObj = handlers[ i ];
4447
4448                                                 // Don't conflict with Object.prototype properties (#13203)
4449                                                 sel = handleObj.selector + " ";
4450
4451                                                 if ( matches[ sel ] === undefined ) {
4452                                                         matches[ sel ] = handleObj.needsContext ?
4453                                                                 jQuery( sel, this ).index( cur ) >= 0 :
4454                                                                 jQuery.find( sel, this, null, [ cur ] ).length;
4455                                                 }
4456                                                 if ( matches[ sel ] ) {
4457                                                         matches.push( handleObj );
4458                                                 }
4459                                         }
4460                                         if ( matches.length ) {
4461                                                 handlerQueue.push({ elem: cur, handlers: matches });
4462                                         }
4463                                 }
4464                         }
4465                 }
4466
4467                 // Add the remaining (directly-bound) handlers
4468                 if ( delegateCount < handlers.length ) {
4469                         handlerQueue.push({ elem: this, handlers: handlers.slice( delegateCount ) });
4470                 }
4471
4472                 return handlerQueue;
4473         },
4474
4475         // Includes some event props shared by KeyEvent and MouseEvent
4476         props: "altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),
4477
4478         fixHooks: {},
4479
4480         keyHooks: {
4481                 props: "char charCode key keyCode".split(" "),
4482                 filter: function( event, original ) {
4483
4484                         // Add which for key events
4485                         if ( event.which == null ) {
4486                                 event.which = original.charCode != null ? original.charCode : original.keyCode;
4487                         }
4488
4489                         return event;
4490                 }
4491         },
4492
4493         mouseHooks: {
4494                 props: "button buttons clientX clientY offsetX offsetY pageX pageY screenX screenY toElement".split(" "),
4495                 filter: function( event, original ) {
4496                         var eventDoc, doc, body,
4497                                 button = original.button;
4498
4499                         // Calculate pageX/Y if missing and clientX/Y available
4500                         if ( event.pageX == null && original.clientX != null ) {
4501                                 eventDoc = event.target.ownerDocument || document;
4502                                 doc = eventDoc.documentElement;
4503                                 body = eventDoc.body;
4504
4505                                 event.pageX = original.clientX + ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - ( doc && doc.clientLeft || body && body.clientLeft || 0 );
4506                                 event.pageY = original.clientY + ( doc && doc.scrollTop  || body && body.scrollTop  || 0 ) - ( doc && doc.clientTop  || body && body.clientTop  || 0 );
4507                         }
4508
4509                         // Add which for click: 1 === left; 2 === middle; 3 === right
4510                         // Note: button is not normalized, so don't use it
4511                         if ( !event.which && button !== undefined ) {
4512                                 event.which = ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) );
4513                         }
4514
4515                         return event;
4516                 }
4517         },
4518
4519         fix: function( event ) {
4520                 if ( event[ jQuery.expando ] ) {
4521                         return event;
4522                 }
4523
4524                 // Create a writable copy of the event object and normalize some properties
4525                 var i, prop, copy,
4526                         type = event.type,
4527                         originalEvent = event,
4528                         fixHook = this.fixHooks[ type ];
4529
4530                 if ( !fixHook ) {
4531                         this.fixHooks[ type ] = fixHook =
4532                                 rmouseEvent.test( type ) ? this.mouseHooks :
4533                                 rkeyEvent.test( type ) ? this.keyHooks :
4534                                 {};
4535                 }
4536                 copy = fixHook.props ? this.props.concat( fixHook.props ) : this.props;
4537
4538                 event = new jQuery.Event( originalEvent );
4539
4540                 i = copy.length;
4541                 while ( i-- ) {
4542                         prop = copy[ i ];
4543                         event[ prop ] = originalEvent[ prop ];
4544                 }
4545
4546                 // Support: Cordova 2.5 (WebKit) (#13255)
4547                 // All events should have a target; Cordova deviceready doesn't
4548                 if ( !event.target ) {
4549                         event.target = document;
4550                 }
4551
4552                 // Support: Safari 6.0+, Chrome < 28
4553                 // Target should not be a text node (#504, #13143)
4554                 if ( event.target.nodeType === 3 ) {
4555                         event.target = event.target.parentNode;
4556                 }
4557
4558                 return fixHook.filter ? fixHook.filter( event, originalEvent ) : event;
4559         },
4560
4561         special: {
4562                 load: {
4563                         // Prevent triggered image.load events from bubbling to window.load
4564                         noBubble: true
4565                 },
4566                 focus: {
4567                         // Fire native event if possible so blur/focus sequence is correct
4568                         trigger: function() {
4569                                 if ( this !== safeActiveElement() && this.focus ) {
4570                                         this.focus();
4571                                         return false;
4572                                 }
4573                         },
4574                         delegateType: "focusin"
4575                 },
4576                 blur: {
4577                         trigger: function() {
4578                                 if ( this === safeActiveElement() && this.blur ) {
4579                                         this.blur();
4580                                         return false;
4581                                 }
4582                         },
4583                         delegateType: "focusout"
4584                 },
4585                 click: {
4586                         // For checkbox, fire native event so checked state will be right
4587                         trigger: function() {
4588                                 if ( this.type === "checkbox" && this.click && jQuery.nodeName( this, "input" ) ) {
4589                                         this.click();
4590                                         return false;
4591                                 }
4592                         },
4593
4594                         // For cross-browser consistency, don't fire native .click() on links
4595                         _default: function( event ) {
4596                                 return jQuery.nodeName( event.target, "a" );
4597                         }
4598                 },
4599
4600                 beforeunload: {
4601                         postDispatch: function( event ) {
4602
4603                                 // Support: Firefox 20+
4604                                 // Firefox doesn't alert if the returnValue field is not set.
4605                                 if ( event.result !== undefined && event.originalEvent ) {
4606                                         event.originalEvent.returnValue = event.result;
4607                                 }
4608                         }
4609                 }
4610         },
4611
4612         simulate: function( type, elem, event, bubble ) {
4613                 // Piggyback on a donor event to simulate a different one.
4614                 // Fake originalEvent to avoid donor's stopPropagation, but if the
4615                 // simulated event prevents default then we do the same on the donor.
4616                 var e = jQuery.extend(
4617                         new jQuery.Event(),
4618                         event,
4619                         {
4620                                 type: type,
4621                                 isSimulated: true,
4622                                 originalEvent: {}
4623                         }
4624                 );
4625                 if ( bubble ) {
4626                         jQuery.event.trigger( e, null, elem );
4627                 } else {
4628                         jQuery.event.dispatch.call( elem, e );
4629                 }
4630                 if ( e.isDefaultPrevented() ) {
4631                         event.preventDefault();
4632                 }
4633         }
4634 };
4635
4636 jQuery.removeEvent = function( elem, type, handle ) {
4637         if ( elem.removeEventListener ) {
4638                 elem.removeEventListener( type, handle, false );
4639         }
4640 };
4641
4642 jQuery.Event = function( src, props ) {
4643         // Allow instantiation without the 'new' keyword
4644         if ( !(this instanceof jQuery.Event) ) {
4645                 return new jQuery.Event( src, props );
4646         }
4647
4648         // Event object
4649         if ( src && src.type ) {
4650                 this.originalEvent = src;
4651                 this.type = src.type;
4652
4653                 // Events bubbling up the document may have been marked as prevented
4654                 // by a handler lower down the tree; reflect the correct value.
4655                 this.isDefaultPrevented = src.defaultPrevented ||
4656                                 src.defaultPrevented === undefined &&
4657                                 // Support: Android < 4.0
4658                                 src.returnValue === false ?
4659                         returnTrue :
4660                         returnFalse;
4661
4662         // Event type
4663         } else {
4664                 this.type = src;
4665         }
4666
4667         // Put explicitly provided properties onto the event object
4668         if ( props ) {
4669                 jQuery.extend( this, props );
4670         }
4671
4672         // Create a timestamp if incoming event doesn't have one
4673         this.timeStamp = src && src.timeStamp || jQuery.now();
4674
4675         // Mark it as fixed
4676         this[ jQuery.expando ] = true;
4677 };
4678
4679 // jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding
4680 // http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html
4681 jQuery.Event.prototype = {
4682         isDefaultPrevented: returnFalse,
4683         isPropagationStopped: returnFalse,
4684         isImmediatePropagationStopped: returnFalse,
4685
4686         preventDefault: function() {
4687                 var e = this.originalEvent;
4688
4689                 this.isDefaultPrevented = returnTrue;
4690
4691                 if ( e && e.preventDefault ) {
4692                         e.preventDefault();
4693                 }
4694         },
4695         stopPropagation: function() {
4696                 var e = this.originalEvent;
4697
4698                 this.isPropagationStopped = returnTrue;
4699
4700                 if ( e && e.stopPropagation ) {
4701                         e.stopPropagation();
4702                 }
4703         },
4704         stopImmediatePropagation: function() {
4705                 var e = this.originalEvent;
4706
4707                 this.isImmediatePropagationStopped = returnTrue;
4708
4709                 if ( e && e.stopImmediatePropagation ) {
4710                         e.stopImmediatePropagation();
4711                 }
4712
4713                 this.stopPropagation();
4714         }
4715 };
4716
4717 // Create mouseenter/leave events using mouseover/out and event-time checks
4718 // Support: Chrome 15+
4719 jQuery.each({
4720         mouseenter: "mouseover",
4721         mouseleave: "mouseout",
4722         pointerenter: "pointerover",
4723         pointerleave: "pointerout"
4724 }, function( orig, fix ) {
4725         jQuery.event.special[ orig ] = {
4726                 delegateType: fix,
4727                 bindType: fix,
4728
4729                 handle: function( event ) {
4730                         var ret,
4731                                 target = this,
4732                                 related = event.relatedTarget,
4733                                 handleObj = event.handleObj;
4734
4735                         // For mousenter/leave call the handler if related is outside the target.
4736                         // NB: No relatedTarget if the mouse left/entered the browser window
4737                         if ( !related || (related !== target && !jQuery.contains( target, related )) ) {
4738                                 event.type = handleObj.origType;
4739                                 ret = handleObj.handler.apply( this, arguments );
4740                                 event.type = fix;
4741                         }
4742                         return ret;
4743                 }
4744         };
4745 });
4746
4747 // Create "bubbling" focus and blur events
4748 // Support: Firefox, Chrome, Safari
4749 if ( !support.focusinBubbles ) {
4750         jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) {
4751
4752                 // Attach a single capturing handler on the document while someone wants focusin/focusout
4753                 var handler = function( event ) {
4754                                 jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ), true );
4755                         };
4756
4757                 jQuery.event.special[ fix ] = {
4758                         setup: function() {
4759                                 var doc = this.ownerDocument || this,
4760                                         attaches = data_priv.access( doc, fix );
4761
4762                                 if ( !attaches ) {
4763                                         doc.addEventListener( orig, handler, true );
4764                                 }
4765                                 data_priv.access( doc, fix, ( attaches || 0 ) + 1 );
4766                         },
4767                         teardown: function() {
4768                                 var doc = this.ownerDocument || this,
4769                                         attaches = data_priv.access( doc, fix ) - 1;
4770
4771                                 if ( !attaches ) {
4772                                         doc.removeEventListener( orig, handler, true );
4773                                         data_priv.remove( doc, fix );
4774
4775                                 } else {
4776                                         data_priv.access( doc, fix, attaches );
4777                                 }
4778                         }
4779                 };
4780         });
4781 }
4782
4783 jQuery.fn.extend({
4784
4785         on: function( types, selector, data, fn, /*INTERNAL*/ one ) {
4786                 var origFn, type;
4787
4788                 // Types can be a map of types/handlers
4789                 if ( typeof types === "object" ) {
4790                         // ( types-Object, selector, data )
4791                         if ( typeof selector !== "string" ) {
4792                                 // ( types-Object, data )
4793                                 data = data || selector;
4794                                 selector = undefined;
4795                         }
4796                         for ( type in types ) {
4797                                 this.on( type, selector, data, types[ type ], one );
4798                         }
4799                         return this;
4800                 }
4801
4802                 if ( data == null && fn == null ) {
4803                         // ( types, fn )
4804                         fn = selector;
4805                         data = selector = undefined;
4806                 } else if ( fn == null ) {
4807                         if ( typeof selector === "string" ) {
4808                                 // ( types, selector, fn )
4809                                 fn = data;
4810                                 data = undefined;
4811                         } else {
4812                                 // ( types, data, fn )
4813                                 fn = data;
4814                                 data = selector;
4815                                 selector = undefined;
4816                         }
4817                 }
4818                 if ( fn === false ) {
4819                         fn = returnFalse;
4820                 } else if ( !fn ) {
4821                         return this;
4822                 }
4823
4824                 if ( one === 1 ) {
4825                         origFn = fn;
4826                         fn = function( event ) {
4827                                 // Can use an empty set, since event contains the info
4828                                 jQuery().off( event );
4829                                 return origFn.apply( this, arguments );
4830                         };
4831                         // Use same guid so caller can remove using origFn
4832                         fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ );
4833                 }
4834                 return this.each( function() {
4835                         jQuery.event.add( this, types, fn, data, selector );
4836                 });
4837         },
4838         one: function( types, selector, data, fn ) {
4839                 return this.on( types, selector, data, fn, 1 );
4840         },
4841         off: function( types, selector, fn ) {
4842                 var handleObj, type;
4843                 if ( types && types.preventDefault && types.handleObj ) {
4844                         // ( event )  dispatched jQuery.Event
4845                         handleObj = types.handleObj;
4846                         jQuery( types.delegateTarget ).off(
4847                                 handleObj.namespace ? handleObj.origType + "." + handleObj.namespace : handleObj.origType,
4848                                 handleObj.selector,
4849                                 handleObj.handler
4850                         );
4851                         return this;
4852                 }
4853                 if ( typeof types === "object" ) {
4854                         // ( types-object [, selector] )
4855                         for ( type in types ) {
4856                                 this.off( type, selector, types[ type ] );
4857                         }
4858                         return this;
4859                 }
4860                 if ( selector === false || typeof selector === "function" ) {
4861                         // ( types [, fn] )
4862                         fn = selector;
4863                         selector = undefined;
4864                 }
4865                 if ( fn === false ) {
4866                         fn = returnFalse;
4867                 }
4868                 return this.each(function() {
4869                         jQuery.event.remove( this, types, fn, selector );
4870                 });
4871         },
4872
4873         trigger: function( type, data ) {
4874                 return this.each(function() {
4875                         jQuery.event.trigger( type, data, this );
4876                 });
4877         },
4878         triggerHandler: function( type, data ) {
4879                 var elem = this[0];
4880                 if ( elem ) {
4881                         return jQuery.event.trigger( type, data, elem, true );
4882                 }
4883         }
4884 });
4885
4886
4887 var
4888         rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,
4889         rtagName = /<([\w:]+)/,
4890         rhtml = /<|&#?\w+;/,
4891         rnoInnerhtml = /<(?:script|style|link)/i,
4892         // checked="checked" or checked
4893         rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i,
4894         rscriptType = /^$|\/(?:java|ecma)script/i,
4895         rscriptTypeMasked = /^true\/(.*)/,
4896         rcleanScript = /^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g,
4897
4898         // We have to close these tags to support XHTML (#13200)
4899         wrapMap = {
4900
4901                 // Support: IE 9
4902                 option: [ 1, "<select multiple='multiple'>", "</select>" ],
4903
4904                 thead: [ 1, "<table>", "</table>" ],
4905                 col: [ 2, "<table><colgroup>", "</colgroup></table>" ],
4906                 tr: [ 2, "<table><tbody>", "</tbody></table>" ],
4907                 td: [ 3, "<table><tbody><tr>", "</tr></tbody></table>" ],
4908
4909                 _default: [ 0, "", "" ]
4910         };
4911
4912 // Support: IE 9
4913 wrapMap.optgroup = wrapMap.option;
4914
4915 wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
4916 wrapMap.th = wrapMap.td;
4917
4918 // Support: 1.x compatibility
4919 // Manipulating tables requires a tbody
4920 function manipulationTarget( elem, content ) {
4921         return jQuery.nodeName( elem, "table" ) &&
4922                 jQuery.nodeName( content.nodeType !== 11 ? content : content.firstChild, "tr" ) ?
4923
4924                 elem.getElementsByTagName("tbody")[0] ||
4925                         elem.appendChild( elem.ownerDocument.createElement("tbody") ) :
4926                 elem;
4927 }
4928
4929 // Replace/restore the type attribute of script elements for safe DOM manipulation
4930 function disableScript( elem ) {
4931         elem.type = (elem.getAttribute("type") !== null) + "/" + elem.type;
4932         return elem;
4933 }
4934 function restoreScript( elem ) {
4935         var match = rscriptTypeMasked.exec( elem.type );
4936
4937         if ( match ) {
4938                 elem.type = match[ 1 ];
4939         } else {
4940                 elem.removeAttribute("type");
4941         }
4942
4943         return elem;
4944 }
4945
4946 // Mark scripts as having already been evaluated
4947 function setGlobalEval( elems, refElements ) {
4948         var i = 0,
4949                 l = elems.length;
4950
4951         for ( ; i < l; i++ ) {
4952                 data_priv.set(
4953                         elems[ i ], "globalEval", !refElements || data_priv.get( refElements[ i ], "globalEval" )
4954                 );
4955         }
4956 }
4957
4958 function cloneCopyEvent( src, dest ) {
4959         var i, l, type, pdataOld, pdataCur, udataOld, udataCur, events;
4960
4961         if ( dest.nodeType !== 1 ) {
4962                 return;
4963         }
4964
4965         // 1. Copy private data: events, handlers, etc.
4966         if ( data_priv.hasData( src ) ) {
4967                 pdataOld = data_priv.access( src );
4968                 pdataCur = data_priv.set( dest, pdataOld );
4969                 events = pdataOld.events;
4970
4971                 if ( events ) {
4972                         delete pdataCur.handle;
4973                         pdataCur.events = {};
4974
4975                         for ( type in events ) {
4976                                 for ( i = 0, l = events[ type ].length; i < l; i++ ) {
4977                                         jQuery.event.add( dest, type, events[ type ][ i ] );
4978                                 }
4979                         }
4980                 }
4981         }
4982
4983         // 2. Copy user data
4984         if ( data_user.hasData( src ) ) {
4985                 udataOld = data_user.access( src );
4986                 udataCur = jQuery.extend( {}, udataOld );
4987
4988                 data_user.set( dest, udataCur );
4989         }
4990 }
4991
4992 function getAll( context, tag ) {
4993         var ret = context.getElementsByTagName ? context.getElementsByTagName( tag || "*" ) :
4994                         context.querySelectorAll ? context.querySelectorAll( tag || "*" ) :
4995                         [];
4996
4997         return tag === undefined || tag && jQuery.nodeName( context, tag ) ?
4998                 jQuery.merge( [ context ], ret ) :
4999                 ret;
5000 }
5001
5002 // Support: IE >= 9
5003 function fixInput( src, dest ) {
5004         var nodeName = dest.nodeName.toLowerCase();
5005
5006         // Fails to persist the checked state of a cloned checkbox or radio button.
5007         if ( nodeName === "input" && rcheckableType.test( src.type ) ) {
5008                 dest.checked = src.checked;
5009
5010         // Fails to return the selected option to the default selected state when cloning options
5011         } else if ( nodeName === "input" || nodeName === "textarea" ) {
5012                 dest.defaultValue = src.defaultValue;
5013         }
5014 }
5015
5016 jQuery.extend({
5017         clone: function( elem, dataAndEvents, deepDataAndEvents ) {
5018                 var i, l, srcElements, destElements,
5019                         clone = elem.cloneNode( true ),
5020                         inPage = jQuery.contains( elem.ownerDocument, elem );
5021
5022                 // Support: IE >= 9
5023                 // Fix Cloning issues
5024                 if ( !support.noCloneChecked && ( elem.nodeType === 1 || elem.nodeType === 11 ) &&
5025                                 !jQuery.isXMLDoc( elem ) ) {
5026
5027                         // We eschew Sizzle here for performance reasons: http://jsperf.com/getall-vs-sizzle/2
5028                         destElements = getAll( clone );
5029                         srcElements = getAll( elem );
5030
5031                         for ( i = 0, l = srcElements.length; i < l; i++ ) {
5032                                 fixInput( srcElements[ i ], destElements[ i ] );
5033                         }
5034                 }
5035
5036                 // Copy the events from the original to the clone
5037                 if ( dataAndEvents ) {
5038                         if ( deepDataAndEvents ) {
5039                                 srcElements = srcElements || getAll( elem );
5040                                 destElements = destElements || getAll( clone );
5041
5042                                 for ( i = 0, l = srcElements.length; i < l; i++ ) {
5043                                         cloneCopyEvent( srcElements[ i ], destElements[ i ] );
5044                                 }
5045                         } else {
5046                                 cloneCopyEvent( elem, clone );
5047                         }
5048                 }
5049
5050                 // Preserve script evaluation history
5051                 destElements = getAll( clone, "script" );
5052                 if ( destElements.length > 0 ) {
5053                         setGlobalEval( destElements, !inPage && getAll( elem, "script" ) );
5054                 }
5055
5056                 // Return the cloned set
5057                 return clone;
5058         },
5059
5060         buildFragment: function( elems, context, scripts, selection ) {
5061                 var elem, tmp, tag, wrap, contains, j,
5062                         fragment = context.createDocumentFragment(),
5063                         nodes = [],
5064                         i = 0,
5065                         l = elems.length;
5066
5067                 for ( ; i < l; i++ ) {
5068                         elem = elems[ i ];
5069
5070                         if ( elem || elem === 0 ) {
5071
5072                                 // Add nodes directly
5073                                 if ( jQuery.type( elem ) === "object" ) {
5074                                         // Support: QtWebKit
5075                                         // jQuery.merge because push.apply(_, arraylike) throws
5076                                         jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem );
5077
5078                                 // Convert non-html into a text node
5079                                 } else if ( !rhtml.test( elem ) ) {
5080                                         nodes.push( context.createTextNode( elem ) );
5081
5082                                 // Convert html into DOM nodes
5083                                 } else {
5084                                         tmp = tmp || fragment.appendChild( context.createElement("div") );
5085
5086                                         // Deserialize a standard representation
5087                                         tag = ( rtagName.exec( elem ) || [ "", "" ] )[ 1 ].toLowerCase();
5088                                         wrap = wrapMap[ tag ] || wrapMap._default;
5089                                         tmp.innerHTML = wrap[ 1 ] + elem.replace( rxhtmlTag, "<$1></$2>" ) + wrap[ 2 ];
5090
5091                                         // Descend through wrappers to the right content
5092                                         j = wrap[ 0 ];
5093                                         while ( j-- ) {
5094                                                 tmp = tmp.lastChild;
5095                                         }
5096
5097                                         // Support: QtWebKit
5098                                         // jQuery.merge because push.apply(_, arraylike) throws
5099                                         jQuery.merge( nodes, tmp.childNodes );
5100
5101                                         // Remember the top-level container
5102                                         tmp = fragment.firstChild;
5103
5104                                         // Fixes #12346
5105                                         // Support: Webkit, IE
5106                                         tmp.textContent = "";
5107                                 }
5108                         }
5109                 }
5110
5111                 // Remove wrapper from fragment
5112                 fragment.textContent = "";
5113
5114                 i = 0;
5115                 while ( (elem = nodes[ i++ ]) ) {
5116
5117                         // #4087 - If origin and destination elements are the same, and this is
5118                         // that element, do not do anything
5119                         if ( selection && jQuery.inArray( elem, selection ) !== -1 ) {
5120                                 continue;
5121                         }
5122
5123                         contains = jQuery.contains( elem.ownerDocument, elem );
5124
5125                         // Append to fragment
5126                         tmp = getAll( fragment.appendChild( elem ), "script" );
5127
5128                         // Preserve script evaluation history
5129                         if ( contains ) {
5130                                 setGlobalEval( tmp );
5131                         }
5132
5133                         // Capture executables
5134                         if ( scripts ) {
5135                                 j = 0;
5136                                 while ( (elem = tmp[ j++ ]) ) {
5137                                         if ( rscriptType.test( elem.type || "" ) ) {
5138                                                 scripts.push( elem );
5139                                         }
5140                                 }
5141                         }
5142                 }
5143
5144                 return fragment;
5145         },
5146
5147         cleanData: function( elems ) {
5148                 var data, elem, type, key,
5149                         special = jQuery.event.special,
5150                         i = 0;
5151
5152                 for ( ; (elem = elems[ i ]) !== undefined; i++ ) {
5153                         if ( jQuery.acceptData( elem ) ) {
5154                                 key = elem[ data_priv.expando ];
5155
5156                                 if ( key && (data = data_priv.cache[ key ]) ) {
5157                                         if ( data.events ) {
5158                                                 for ( type in data.events ) {
5159                                                         if ( special[ type ] ) {
5160                                                                 jQuery.event.remove( elem, type );
5161
5162                                                         // This is a shortcut to avoid jQuery.event.remove's overhead
5163                                                         } else {
5164                                                                 jQuery.removeEvent( elem, type, data.handle );
5165                                                         }
5166                                                 }
5167                                         }
5168                                         if ( data_priv.cache[ key ] ) {
5169                                                 // Discard any remaining `private` data
5170                                                 delete data_priv.cache[ key ];
5171                                         }
5172                                 }
5173                         }
5174                         // Discard any remaining `user` data
5175                         delete data_user.cache[ elem[ data_user.expando ] ];
5176                 }
5177         }
5178 });
5179
5180 jQuery.fn.extend({
5181         text: function( value ) {
5182                 return access( this, function( value ) {
5183                         return value === undefined ?
5184                                 jQuery.text( this ) :
5185                                 this.empty().each(function() {
5186                                         if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
5187                                                 this.textContent = value;
5188                                         }
5189                                 });
5190                 }, null, value, arguments.length );
5191         },
5192
5193         append: function() {
5194                 return this.domManip( arguments, function( elem ) {
5195                         if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
5196                                 var target = manipulationTarget( this, elem );
5197                                 target.appendChild( elem );
5198                         }
5199                 });
5200         },
5201
5202         prepend: function() {
5203                 return this.domManip( arguments, function( elem ) {
5204                         if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
5205                                 var target = manipulationTarget( this, elem );
5206                                 target.insertBefore( elem, target.firstChild );
5207                         }
5208                 });
5209         },
5210
5211         before: function() {
5212                 return this.domManip( arguments, function( elem ) {
5213                         if ( this.parentNode ) {
5214                                 this.parentNode.insertBefore( elem, this );
5215                         }
5216                 });
5217         },
5218
5219         after: function() {
5220                 return this.domManip( arguments, function( elem ) {
5221                         if ( this.parentNode ) {
5222                                 this.parentNode.insertBefore( elem, this.nextSibling );
5223                         }
5224                 });
5225         },
5226
5227         remove: function( selector, keepData /* Internal Use Only */ ) {
5228                 var elem,
5229                         elems = selector ? jQuery.filter( selector, this ) : this,
5230                         i = 0;
5231
5232                 for ( ; (elem = elems[i]) != null; i++ ) {
5233                         if ( !keepData && elem.nodeType === 1 ) {
5234                                 jQuery.cleanData( getAll( elem ) );
5235                         }
5236
5237                         if ( elem.parentNode ) {
5238                                 if ( keepData && jQuery.contains( elem.ownerDocument, elem ) ) {
5239                                         setGlobalEval( getAll( elem, "script" ) );
5240                                 }
5241                                 elem.parentNode.removeChild( elem );
5242                         }
5243                 }
5244
5245                 return this;
5246         },
5247
5248         empty: function() {
5249                 var elem,
5250                         i = 0;
5251
5252                 for ( ; (elem = this[i]) != null; i++ ) {
5253                         if ( elem.nodeType === 1 ) {
5254
5255                                 // Prevent memory leaks
5256                                 jQuery.cleanData( getAll( elem, false ) );
5257
5258                                 // Remove any remaining nodes
5259                                 elem.textContent = "";
5260                         }
5261                 }
5262
5263                 return this;
5264         },
5265
5266         clone: function( dataAndEvents, deepDataAndEvents ) {
5267                 dataAndEvents = dataAndEvents == null ? false : dataAndEvents;
5268                 deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents;
5269
5270                 return this.map(function() {
5271                         return jQuery.clone( this, dataAndEvents, deepDataAndEvents );
5272                 });
5273         },
5274
5275         html: function( value ) {
5276                 return access( this, function( value ) {
5277                         var elem = this[ 0 ] || {},
5278                                 i = 0,
5279                                 l = this.length;
5280
5281                         if ( value === undefined && elem.nodeType === 1 ) {
5282                                 return elem.innerHTML;
5283                         }
5284
5285                         // See if we can take a shortcut and just use innerHTML
5286                         if ( typeof value === "string" && !rnoInnerhtml.test( value ) &&
5287                                 !wrapMap[ ( rtagName.exec( value ) || [ "", "" ] )[ 1 ].toLowerCase() ] ) {
5288
5289                                 value = value.replace( rxhtmlTag, "<$1></$2>" );
5290
5291                                 try {
5292                                         for ( ; i < l; i++ ) {
5293                                                 elem = this[ i ] || {};
5294
5295                                                 // Remove element nodes and prevent memory leaks
5296                                                 if ( elem.nodeType === 1 ) {
5297                                                         jQuery.cleanData( getAll( elem, false ) );
5298                                                         elem.innerHTML = value;
5299                                                 }
5300                                         }
5301
5302                                         elem = 0;
5303
5304                                 // If using innerHTML throws an exception, use the fallback method
5305                                 } catch( e ) {}
5306                         }
5307
5308                         if ( elem ) {
5309                                 this.empty().append( value );
5310                         }
5311                 }, null, value, arguments.length );
5312         },
5313
5314         replaceWith: function() {
5315                 var arg = arguments[ 0 ];
5316
5317                 // Make the changes, replacing each context element with the new content
5318                 this.domManip( arguments, function( elem ) {
5319                         arg = this.parentNode;
5320
5321                         jQuery.cleanData( getAll( this ) );
5322
5323                         if ( arg ) {
5324                                 arg.replaceChild( elem, this );
5325                         }
5326                 });
5327
5328                 // Force removal if there was no new content (e.g., from empty arguments)
5329                 return arg && (arg.length || arg.nodeType) ? this : this.remove();
5330         },
5331
5332         detach: function( selector ) {
5333                 return this.remove( selector, true );
5334         },
5335
5336         domManip: function( args, callback ) {
5337
5338                 // Flatten any nested arrays
5339                 args = concat.apply( [], args );
5340
5341                 var fragment, first, scripts, hasScripts, node, doc,
5342                         i = 0,
5343                         l = this.length,
5344                         set = this,
5345                         iNoClone = l - 1,
5346                         value = args[ 0 ],
5347                         isFunction = jQuery.isFunction( value );
5348
5349                 // We can't cloneNode fragments that contain checked, in WebKit
5350                 if ( isFunction ||
5351                                 ( l > 1 && typeof value === "string" &&
5352                                         !support.checkClone && rchecked.test( value ) ) ) {
5353                         return this.each(function( index ) {
5354                                 var self = set.eq( index );
5355                                 if ( isFunction ) {
5356                                         args[ 0 ] = value.call( this, index, self.html() );
5357                                 }
5358                                 self.domManip( args, callback );
5359                         });
5360                 }
5361
5362                 if ( l ) {
5363                         fragment = jQuery.buildFragment( args, this[ 0 ].ownerDocument, false, this );
5364                         first = fragment.firstChild;
5365
5366                         if ( fragment.childNodes.length === 1 ) {
5367                                 fragment = first;
5368                         }
5369
5370                         if ( first ) {
5371                                 scripts = jQuery.map( getAll( fragment, "script" ), disableScript );
5372                                 hasScripts = scripts.length;
5373
5374                                 // Use the original fragment for the last item instead of the first because it can end up
5375                                 // being emptied incorrectly in certain situations (#8070).
5376                                 for ( ; i < l; i++ ) {
5377                                         node = fragment;
5378
5379                                         if ( i !== iNoClone ) {
5380                                                 node = jQuery.clone( node, true, true );
5381
5382                                                 // Keep references to cloned scripts for later restoration
5383                                                 if ( hasScripts ) {
5384                                                         // Support: QtWebKit
5385                                                         // jQuery.merge because push.apply(_, arraylike) throws
5386                                                         jQuery.merge( scripts, getAll( node, "script" ) );
5387                                                 }
5388                                         }
5389
5390                                         callback.call( this[ i ], node, i );
5391                                 }
5392
5393                                 if ( hasScripts ) {
5394                                         doc = scripts[ scripts.length - 1 ].ownerDocument;
5395
5396                                         // Reenable scripts
5397                                         jQuery.map( scripts, restoreScript );
5398
5399                                         // Evaluate executable scripts on first document insertion
5400                                         for ( i = 0; i < hasScripts; i++ ) {
5401                                                 node = scripts[ i ];
5402                                                 if ( rscriptType.test( node.type || "" ) &&
5403                                                         !data_priv.access( node, "globalEval" ) && jQuery.contains( doc, node ) ) {
5404
5405                                                         if ( node.src ) {
5406                                                                 // Optional AJAX dependency, but won't run scripts if not present
5407                                                                 if ( jQuery._evalUrl ) {
5408                                                                         jQuery._evalUrl( node.src );
5409                                                                 }
5410                                                         } else {
5411                                                                 jQuery.globalEval( node.textContent.replace( rcleanScript, "" ) );
5412                                                         }
5413                                                 }
5414                                         }
5415                                 }
5416                         }
5417                 }
5418
5419                 return this;
5420         }
5421 });
5422
5423 jQuery.each({
5424         appendTo: "append",
5425         prependTo: "prepend",
5426         insertBefore: "before",
5427         insertAfter: "after",
5428         replaceAll: "replaceWith"
5429 }, function( name, original ) {
5430         jQuery.fn[ name ] = function( selector ) {
5431                 var elems,
5432                         ret = [],
5433                         insert = jQuery( selector ),
5434                         last = insert.length - 1,
5435                         i = 0;
5436
5437                 for ( ; i <= last; i++ ) {
5438                         elems = i === last ? this : this.clone( true );
5439                         jQuery( insert[ i ] )[ original ]( elems );
5440
5441                         // Support: QtWebKit
5442                         // .get() because push.apply(_, arraylike) throws
5443                         push.apply( ret, elems.get() );
5444                 }
5445
5446                 return this.pushStack( ret );
5447         };
5448 });
5449
5450
5451 var iframe,
5452         elemdisplay = {};
5453
5454 /**
5455  * Retrieve the actual display of a element
5456  * @param {String} name nodeName of the element
5457  * @param {Object} doc Document object
5458  */
5459 // Called only from within defaultDisplay
5460 function actualDisplay( name, doc ) {
5461         var style,
5462                 elem = jQuery( doc.createElement( name ) ).appendTo( doc.body ),
5463
5464                 // getDefaultComputedStyle might be reliably used only on attached element
5465                 display = window.getDefaultComputedStyle && ( style = window.getDefaultComputedStyle( elem[ 0 ] ) ) ?
5466
5467                         // Use of this method is a temporary fix (more like optmization) until something better comes along,
5468                         // since it was removed from specification and supported only in FF
5469                         style.display : jQuery.css( elem[ 0 ], "display" );
5470
5471         // We don't have any data stored on the element,
5472         // so use "detach" method as fast way to get rid of the element
5473         elem.detach();
5474
5475         return display;
5476 }
5477
5478 /**
5479  * Try to determine the default display value of an element
5480  * @param {String} nodeName
5481  */
5482 function defaultDisplay( nodeName ) {
5483         var doc = document,
5484                 display = elemdisplay[ nodeName ];
5485
5486         if ( !display ) {
5487                 display = actualDisplay( nodeName, doc );
5488
5489                 // If the simple way fails, read from inside an iframe
5490                 if ( display === "none" || !display ) {
5491
5492                         // Use the already-created iframe if possible
5493                         iframe = (iframe || jQuery( "<iframe frameborder='0' width='0' height='0'/>" )).appendTo( doc.documentElement );
5494
5495                         // Always write a new HTML skeleton so Webkit and Firefox don't choke on reuse
5496                         doc = iframe[ 0 ].contentDocument;
5497
5498                         // Support: IE
5499                         doc.write();
5500                         doc.close();
5501
5502                         display = actualDisplay( nodeName, doc );
5503                         iframe.detach();
5504                 }
5505
5506                 // Store the correct default display
5507                 elemdisplay[ nodeName ] = display;
5508         }
5509
5510         return display;
5511 }
5512 var rmargin = (/^margin/);
5513
5514 var rnumnonpx = new RegExp( "^(" + pnum + ")(?!px)[a-z%]+$", "i" );
5515
5516 var getStyles = function( elem ) {
5517                 return elem.ownerDocument.defaultView.getComputedStyle( elem, null );
5518         };
5519
5520
5521
5522 function curCSS( elem, name, computed ) {
5523         var width, minWidth, maxWidth, ret,
5524                 style = elem.style;
5525
5526         computed = computed || getStyles( elem );
5527
5528         // Support: IE9
5529         // getPropertyValue is only needed for .css('filter') in IE9, see #12537
5530         if ( computed ) {
5531                 ret = computed.getPropertyValue( name ) || computed[ name ];
5532         }
5533
5534         if ( computed ) {
5535
5536                 if ( ret === "" && !jQuery.contains( elem.ownerDocument, elem ) ) {
5537                         ret = jQuery.style( elem, name );
5538                 }
5539
5540                 // Support: iOS < 6
5541                 // A tribute to the "awesome hack by Dean Edwards"
5542                 // iOS < 6 (at least) returns percentage for a larger set of values, but width seems to be reliably pixels
5543                 // this is against the CSSOM draft spec: http://dev.w3.org/csswg/cssom/#resolved-values
5544                 if ( rnumnonpx.test( ret ) && rmargin.test( name ) ) {
5545
5546                         // Remember the original values
5547                         width = style.width;
5548                         minWidth = style.minWidth;
5549                         maxWidth = style.maxWidth;
5550
5551                         // Put in the new values to get a computed value out
5552                         style.minWidth = style.maxWidth = style.width = ret;
5553                         ret = computed.width;
5554
5555                         // Revert the changed values
5556                         style.width = width;
5557                         style.minWidth = minWidth;
5558                         style.maxWidth = maxWidth;
5559                 }
5560         }
5561
5562         return ret !== undefined ?
5563                 // Support: IE
5564                 // IE returns zIndex value as an integer.
5565                 ret + "" :
5566                 ret;
5567 }
5568
5569
5570 function addGetHookIf( conditionFn, hookFn ) {
5571         // Define the hook, we'll check on the first run if it's really needed.
5572         return {
5573                 get: function() {
5574                         if ( conditionFn() ) {
5575                                 // Hook not needed (or it's not possible to use it due to missing dependency),
5576                                 // remove it.
5577                                 // Since there are no other hooks for marginRight, remove the whole object.
5578                                 delete this.get;
5579                                 return;
5580                         }
5581
5582                         // Hook needed; redefine it so that the support test is not executed again.
5583
5584                         return (this.get = hookFn).apply( this, arguments );
5585                 }
5586         };
5587 }
5588
5589
5590 (function() {
5591         var pixelPositionVal, boxSizingReliableVal,
5592                 docElem = document.documentElement,
5593                 container = document.createElement( "div" ),
5594                 div = document.createElement( "div" );
5595
5596         if ( !div.style ) {
5597                 return;
5598         }
5599
5600         div.style.backgroundClip = "content-box";
5601         div.cloneNode( true ).style.backgroundClip = "";
5602         support.clearCloneStyle = div.style.backgroundClip === "content-box";
5603
5604         container.style.cssText = "border:0;width:0;height:0;top:0;left:-9999px;margin-top:1px;" +
5605                 "position:absolute";
5606         container.appendChild( div );
5607
5608         // Executing both pixelPosition & boxSizingReliable tests require only one layout
5609         // so they're executed at the same time to save the second computation.
5610         function computePixelPositionAndBoxSizingReliable() {
5611                 div.style.cssText =
5612                         // Support: Firefox<29, Android 2.3
5613                         // Vendor-prefix box-sizing
5614                         "-webkit-box-sizing:border-box;-moz-box-sizing:border-box;" +
5615                         "box-sizing:border-box;display:block;margin-top:1%;top:1%;" +
5616                         "border:1px;padding:1px;width:4px;position:absolute";
5617                 div.innerHTML = "";
5618                 docElem.appendChild( container );
5619
5620                 var divStyle = window.getComputedStyle( div, null );
5621                 pixelPositionVal = divStyle.top !== "1%";
5622                 boxSizingReliableVal = divStyle.width === "4px";
5623
5624                 docElem.removeChild( container );
5625         }
5626
5627         // Support: node.js jsdom
5628         // Don't assume that getComputedStyle is a property of the global object
5629         if ( window.getComputedStyle ) {
5630                 jQuery.extend( support, {
5631                         pixelPosition: function() {
5632                                 // This test is executed only once but we still do memoizing
5633                                 // since we can use the boxSizingReliable pre-computing.
5634                                 // No need to check if the test was already performed, though.
5635                                 computePixelPositionAndBoxSizingReliable();
5636                                 return pixelPositionVal;
5637                         },
5638                         boxSizingReliable: function() {
5639                                 if ( boxSizingReliableVal == null ) {
5640                                         computePixelPositionAndBoxSizingReliable();
5641                                 }
5642                                 return boxSizingReliableVal;
5643                         },
5644                         reliableMarginRight: function() {
5645                                 // Support: Android 2.3
5646                                 // Check if div with explicit width and no margin-right incorrectly
5647                                 // gets computed margin-right based on width of container. (#3333)
5648                                 // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
5649                                 // This support function is only executed once so no memoizing is needed.
5650                                 var ret,
5651                                         marginDiv = div.appendChild( document.createElement( "div" ) );
5652
5653                                 // Reset CSS: box-sizing; display; margin; border; padding
5654                                 marginDiv.style.cssText = div.style.cssText =
5655                                         // Support: Firefox<29, Android 2.3
5656                                         // Vendor-prefix box-sizing
5657                                         "-webkit-box-sizing:content-box;-moz-box-sizing:content-box;" +
5658                                         "box-sizing:content-box;display:block;margin:0;border:0;padding:0";
5659                                 marginDiv.style.marginRight = marginDiv.style.width = "0";
5660                                 div.style.width = "1px";
5661                                 docElem.appendChild( container );
5662
5663                                 ret = !parseFloat( window.getComputedStyle( marginDiv, null ).marginRight );
5664
5665                                 docElem.removeChild( container );
5666
5667                                 return ret;
5668                         }
5669                 });
5670         }
5671 })();
5672
5673
5674 // A method for quickly swapping in/out CSS properties to get correct calculations.
5675 jQuery.swap = function( elem, options, callback, args ) {
5676         var ret, name,
5677                 old = {};
5678
5679         // Remember the old values, and insert the new ones
5680         for ( name in options ) {
5681                 old[ name ] = elem.style[ name ];
5682                 elem.style[ name ] = options[ name ];
5683         }
5684
5685         ret = callback.apply( elem, args || [] );
5686
5687         // Revert the old values
5688         for ( name in options ) {
5689                 elem.style[ name ] = old[ name ];
5690         }
5691
5692         return ret;
5693 };
5694
5695
5696 var
5697         // swappable if display is none or starts with table except "table", "table-cell", or "table-caption"
5698         // see here for display values: https://developer.mozilla.org/en-US/docs/CSS/display
5699         rdisplayswap = /^(none|table(?!-c[ea]).+)/,
5700         rnumsplit = new RegExp( "^(" + pnum + ")(.*)$", "i" ),
5701         rrelNum = new RegExp( "^([+-])=(" + pnum + ")", "i" ),
5702
5703         cssShow = { position: "absolute", visibility: "hidden", display: "block" },
5704         cssNormalTransform = {
5705                 letterSpacing: "0",
5706                 fontWeight: "400"
5707         },
5708
5709         cssPrefixes = [ "Webkit", "O", "Moz", "ms" ];
5710
5711 // return a css property mapped to a potentially vendor prefixed property
5712 function vendorPropName( style, name ) {
5713
5714         // shortcut for names that are not vendor prefixed
5715         if ( name in style ) {
5716                 return name;
5717         }
5718
5719         // check for vendor prefixed names
5720         var capName = name[0].toUpperCase() + name.slice(1),
5721                 origName = name,
5722                 i = cssPrefixes.length;
5723
5724         while ( i-- ) {
5725                 name = cssPrefixes[ i ] + capName;
5726                 if ( name in style ) {
5727                         return name;
5728                 }
5729         }
5730
5731         return origName;
5732 }
5733
5734 function setPositiveNumber( elem, value, subtract ) {
5735         var matches = rnumsplit.exec( value );
5736         return matches ?
5737                 // Guard against undefined "subtract", e.g., when used as in cssHooks
5738                 Math.max( 0, matches[ 1 ] - ( subtract || 0 ) ) + ( matches[ 2 ] || "px" ) :
5739                 value;
5740 }
5741
5742 function augmentWidthOrHeight( elem, name, extra, isBorderBox, styles ) {
5743         var i = extra === ( isBorderBox ? "border" : "content" ) ?
5744                 // If we already have the right measurement, avoid augmentation
5745                 4 :
5746                 // Otherwise initialize for horizontal or vertical properties
5747                 name === "width" ? 1 : 0,
5748
5749                 val = 0;
5750
5751         for ( ; i < 4; i += 2 ) {
5752                 // both box models exclude margin, so add it if we want it
5753                 if ( extra === "margin" ) {
5754                         val += jQuery.css( elem, extra + cssExpand[ i ], true, styles );
5755                 }
5756
5757                 if ( isBorderBox ) {
5758                         // border-box includes padding, so remove it if we want content
5759                         if ( extra === "content" ) {
5760                                 val -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles );
5761                         }
5762
5763                         // at this point, extra isn't border nor margin, so remove border
5764                         if ( extra !== "margin" ) {
5765                                 val -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles );
5766                         }
5767                 } else {
5768                         // at this point, extra isn't content, so add padding
5769                         val += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles );
5770
5771                         // at this point, extra isn't content nor padding, so add border
5772                         if ( extra !== "padding" ) {
5773                                 val += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles );
5774                         }
5775                 }
5776         }
5777
5778         return val;
5779 }
5780
5781 function getWidthOrHeight( elem, name, extra ) {
5782
5783         // Start with offset property, which is equivalent to the border-box value
5784         var valueIsBorderBox = true,
5785                 val = name === "width" ? elem.offsetWidth : elem.offsetHeight,
5786                 styles = getStyles( elem ),
5787                 isBorderBox = jQuery.css( elem, "boxSizing", false, styles ) === "border-box";
5788
5789         // some non-html elements return undefined for offsetWidth, so check for null/undefined
5790         // svg - https://bugzilla.mozilla.org/show_bug.cgi?id=649285
5791         // MathML - https://bugzilla.mozilla.org/show_bug.cgi?id=491668
5792         if ( val <= 0 || val == null ) {
5793                 // Fall back to computed then uncomputed css if necessary
5794                 val = curCSS( elem, name, styles );
5795                 if ( val < 0 || val == null ) {
5796                         val = elem.style[ name ];
5797                 }
5798
5799                 // Computed unit is not pixels. Stop here and return.
5800                 if ( rnumnonpx.test(val) ) {
5801                         return val;
5802                 }
5803
5804                 // we need the check for style in case a browser which returns unreliable values
5805                 // for getComputedStyle silently falls back to the reliable elem.style
5806                 valueIsBorderBox = isBorderBox &&
5807                         ( support.boxSizingReliable() || val === elem.style[ name ] );
5808
5809                 // Normalize "", auto, and prepare for extra
5810                 val = parseFloat( val ) || 0;
5811         }
5812
5813         // use the active box-sizing model to add/subtract irrelevant styles
5814         return ( val +
5815                 augmentWidthOrHeight(
5816                         elem,
5817                         name,
5818                         extra || ( isBorderBox ? "border" : "content" ),
5819                         valueIsBorderBox,
5820                         styles
5821                 )
5822         ) + "px";
5823 }
5824
5825 function showHide( elements, show ) {
5826         var display, elem, hidden,
5827                 values = [],
5828                 index = 0,
5829                 length = elements.length;
5830
5831         for ( ; index < length; index++ ) {
5832                 elem = elements[ index ];
5833                 if ( !elem.style ) {
5834                         continue;
5835                 }
5836
5837                 values[ index ] = data_priv.get( elem, "olddisplay" );
5838                 display = elem.style.display;
5839                 if ( show ) {
5840                         // Reset the inline display of this element to learn if it is
5841                         // being hidden by cascaded rules or not
5842                         if ( !values[ index ] && display === "none" ) {
5843                                 elem.style.display = "";
5844                         }
5845
5846                         // Set elements which have been overridden with display: none
5847                         // in a stylesheet to whatever the default browser style is
5848                         // for such an element
5849                         if ( elem.style.display === "" && isHidden( elem ) ) {
5850                                 values[ index ] = data_priv.access( elem, "olddisplay", defaultDisplay(elem.nodeName) );
5851                         }
5852                 } else {
5853                         hidden = isHidden( elem );
5854
5855                         if ( display !== "none" || !hidden ) {
5856                                 data_priv.set( elem, "olddisplay", hidden ? display : jQuery.css( elem, "display" ) );
5857                         }
5858                 }
5859         }
5860
5861         // Set the display of most of the elements in a second loop
5862         // to avoid the constant reflow
5863         for ( index = 0; index < length; index++ ) {
5864                 elem = elements[ index ];
5865                 if ( !elem.style ) {
5866                         continue;
5867                 }
5868                 if ( !show || elem.style.display === "none" || elem.style.display === "" ) {
5869                         elem.style.display = show ? values[ index ] || "" : "none";
5870                 }
5871         }
5872
5873         return elements;
5874 }
5875
5876 jQuery.extend({
5877         // Add in style property hooks for overriding the default
5878         // behavior of getting and setting a style property
5879         cssHooks: {
5880                 opacity: {
5881                         get: function( elem, computed ) {
5882                                 if ( computed ) {
5883                                         // We should always get a number back from opacity
5884                                         var ret = curCSS( elem, "opacity" );
5885                                         return ret === "" ? "1" : ret;
5886                                 }
5887                         }
5888                 }
5889         },
5890
5891         // Don't automatically add "px" to these possibly-unitless properties
5892         cssNumber: {
5893                 "columnCount": true,
5894                 "fillOpacity": true,
5895                 "flexGrow": true,
5896                 "flexShrink": true,
5897                 "fontWeight": true,
5898                 "lineHeight": true,
5899                 "opacity": true,
5900                 "order": true,
5901                 "orphans": true,
5902                 "widows": true,
5903                 "zIndex": true,
5904                 "zoom": true
5905         },
5906
5907         // Add in properties whose names you wish to fix before
5908         // setting or getting the value
5909         cssProps: {
5910                 // normalize float css property
5911                 "float": "cssFloat"
5912         },
5913
5914         // Get and set the style property on a DOM Node
5915         style: function( elem, name, value, extra ) {
5916                 // Don't set styles on text and comment nodes
5917                 if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) {
5918                         return;
5919                 }
5920
5921                 // Make sure that we're working with the right name
5922                 var ret, type, hooks,
5923                         origName = jQuery.camelCase( name ),
5924                         style = elem.style;
5925
5926                 name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( style, origName ) );
5927
5928                 // gets hook for the prefixed version
5929                 // followed by the unprefixed version
5930                 hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];
5931
5932                 // Check if we're setting a value
5933                 if ( value !== undefined ) {
5934                         type = typeof value;
5935
5936                         // convert relative number strings (+= or -=) to relative numbers. #7345
5937                         if ( type === "string" && (ret = rrelNum.exec( value )) ) {
5938                                 value = ( ret[1] + 1 ) * ret[2] + parseFloat( jQuery.css( elem, name ) );
5939                                 // Fixes bug #9237
5940                                 type = "number";
5941                         }
5942
5943                         // Make sure that null and NaN values aren't set. See: #7116
5944                         if ( value == null || value !== value ) {
5945                                 return;
5946                         }
5947
5948                         // If a number was passed in, add 'px' to the (except for certain CSS properties)
5949                         if ( type === "number" && !jQuery.cssNumber[ origName ] ) {
5950                                 value += "px";
5951                         }
5952
5953                         // Fixes #8908, it can be done more correctly by specifying setters in cssHooks,
5954                         // but it would mean to define eight (for every problematic property) identical functions
5955                         if ( !support.clearCloneStyle && value === "" && name.indexOf( "background" ) === 0 ) {
5956                                 style[ name ] = "inherit";
5957                         }
5958
5959                         // If a hook was provided, use that value, otherwise just set the specified value
5960                         if ( !hooks || !("set" in hooks) || (value = hooks.set( elem, value, extra )) !== undefined ) {
5961                                 style[ name ] = value;
5962                         }
5963
5964                 } else {
5965                         // If a hook was provided get the non-computed value from there
5966                         if ( hooks && "get" in hooks && (ret = hooks.get( elem, false, extra )) !== undefined ) {
5967                                 return ret;
5968                         }
5969
5970                         // Otherwise just get the value from the style object
5971                         return style[ name ];
5972                 }
5973         },
5974
5975         css: function( elem, name, extra, styles ) {
5976                 var val, num, hooks,
5977                         origName = jQuery.camelCase( name );
5978
5979                 // Make sure that we're working with the right name
5980                 name = jQuery.cssProps[ origName ] || ( jQuery.cssProps[ origName ] = vendorPropName( elem.style, origName ) );
5981
5982                 // gets hook for the prefixed version
5983                 // followed by the unprefixed version
5984                 hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];
5985
5986                 // If a hook was provided get the computed value from there
5987                 if ( hooks && "get" in hooks ) {
5988                         val = hooks.get( elem, true, extra );
5989                 }
5990
5991                 // Otherwise, if a way to get the computed value exists, use that
5992                 if ( val === undefined ) {
5993                         val = curCSS( elem, name, styles );
5994                 }
5995
5996                 //convert "normal" to computed value
5997                 if ( val === "normal" && name in cssNormalTransform ) {
5998                         val = cssNormalTransform[ name ];
5999                 }
6000
6001                 // Return, converting to number if forced or a qualifier was provided and val looks numeric
6002                 if ( extra === "" || extra ) {
6003                         num = parseFloat( val );
6004                         return extra === true || jQuery.isNumeric( num ) ? num || 0 : val;
6005                 }
6006                 return val;
6007         }
6008 });
6009
6010 jQuery.each([ "height", "width" ], function( i, name ) {
6011         jQuery.cssHooks[ name ] = {
6012                 get: function( elem, computed, extra ) {
6013                         if ( computed ) {
6014                                 // certain elements can have dimension info if we invisibly show them
6015                                 // however, it must have a current display style that would benefit from this
6016                                 return rdisplayswap.test( jQuery.css( elem, "display" ) ) && elem.offsetWidth === 0 ?
6017                                         jQuery.swap( elem, cssShow, function() {
6018                                                 return getWidthOrHeight( elem, name, extra );
6019                                         }) :
6020                                         getWidthOrHeight( elem, name, extra );
6021                         }
6022                 },
6023
6024                 set: function( elem, value, extra ) {
6025                         var styles = extra && getStyles( elem );
6026                         return setPositiveNumber( elem, value, extra ?
6027                                 augmentWidthOrHeight(
6028                                         elem,
6029                                         name,
6030                                         extra,
6031                                         jQuery.css( elem, "boxSizing", false, styles ) === "border-box",
6032                                         styles
6033                                 ) : 0
6034                         );
6035                 }
6036         };
6037 });
6038
6039 // Support: Android 2.3
6040 jQuery.cssHooks.marginRight = addGetHookIf( support.reliableMarginRight,
6041         function( elem, computed ) {
6042                 if ( computed ) {
6043                         // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right
6044                         // Work around by temporarily setting element display to inline-block
6045                         return jQuery.swap( elem, { "display": "inline-block" },
6046                                 curCSS, [ elem, "marginRight" ] );
6047                 }
6048         }
6049 );
6050
6051 // These hooks are used by animate to expand properties
6052 jQuery.each({
6053         margin: "",
6054         padding: "",
6055         border: "Width"
6056 }, function( prefix, suffix ) {
6057         jQuery.cssHooks[ prefix + suffix ] = {
6058                 expand: function( value ) {
6059                         var i = 0,
6060                                 expanded = {},
6061
6062                                 // assumes a single number if not a string
6063                                 parts = typeof value === "string" ? value.split(" ") : [ value ];
6064
6065                         for ( ; i < 4; i++ ) {
6066                                 expanded[ prefix + cssExpand[ i ] + suffix ] =
6067                                         parts[ i ] || parts[ i - 2 ] || parts[ 0 ];
6068                         }
6069
6070                         return expanded;
6071                 }
6072         };
6073
6074         if ( !rmargin.test( prefix ) ) {
6075                 jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber;
6076         }
6077 });
6078
6079 jQuery.fn.extend({
6080         css: function( name, value ) {
6081                 return access( this, function( elem, name, value ) {
6082                         var styles, len,
6083                                 map = {},
6084                                 i = 0;
6085
6086                         if ( jQuery.isArray( name ) ) {
6087                                 styles = getStyles( elem );
6088                                 len = name.length;
6089
6090                                 for ( ; i < len; i++ ) {
6091                                         map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles );
6092                                 }
6093
6094                                 return map;
6095                         }
6096
6097                         return value !== undefined ?
6098                                 jQuery.style( elem, name, value ) :
6099                                 jQuery.css( elem, name );
6100                 }, name, value, arguments.length > 1 );
6101         },
6102         show: function() {
6103                 return showHide( this, true );
6104         },
6105         hide: function() {
6106                 return showHide( this );
6107         },
6108         toggle: function( state ) {
6109                 if ( typeof state === "boolean" ) {
6110                         return state ? this.show() : this.hide();
6111                 }
6112
6113                 return this.each(function() {
6114                         if ( isHidden( this ) ) {
6115                                 jQuery( this ).show();
6116                         } else {
6117                                 jQuery( this ).hide();
6118                         }
6119                 });
6120         }
6121 });
6122
6123
6124 function Tween( elem, options, prop, end, easing ) {
6125         return new Tween.prototype.init( elem, options, prop, end, easing );
6126 }
6127 jQuery.Tween = Tween;
6128
6129 Tween.prototype = {
6130         constructor: Tween,
6131         init: function( elem, options, prop, end, easing, unit ) {
6132                 this.elem = elem;
6133                 this.prop = prop;
6134                 this.easing = easing || "swing";
6135                 this.options = options;
6136                 this.start = this.now = this.cur();
6137                 this.end = end;
6138                 this.unit = unit || ( jQuery.cssNumber[ prop ] ? "" : "px" );
6139         },
6140         cur: function() {
6141                 var hooks = Tween.propHooks[ this.prop ];
6142
6143                 return hooks && hooks.get ?
6144                         hooks.get( this ) :
6145                         Tween.propHooks._default.get( this );
6146         },
6147         run: function( percent ) {
6148                 var eased,
6149                         hooks = Tween.propHooks[ this.prop ];
6150
6151                 if ( this.options.duration ) {
6152                         this.pos = eased = jQuery.easing[ this.easing ](
6153                                 percent, this.options.duration * percent, 0, 1, this.options.duration
6154                         );
6155                 } else {
6156                         this.pos = eased = percent;
6157                 }
6158                 this.now = ( this.end - this.start ) * eased + this.start;
6159
6160                 if ( this.options.step ) {
6161                         this.options.step.call( this.elem, this.now, this );
6162                 }
6163
6164                 if ( hooks && hooks.set ) {
6165                         hooks.set( this );
6166                 } else {
6167                         Tween.propHooks._default.set( this );
6168                 }
6169                 return this;
6170         }
6171 };
6172
6173 Tween.prototype.init.prototype = Tween.prototype;
6174
6175 Tween.propHooks = {
6176         _default: {
6177                 get: function( tween ) {
6178                         var result;
6179
6180                         if ( tween.elem[ tween.prop ] != null &&
6181                                 (!tween.elem.style || tween.elem.style[ tween.prop ] == null) ) {
6182                                 return tween.elem[ tween.prop ];
6183                         }
6184
6185                         // passing an empty string as a 3rd parameter to .css will automatically
6186                         // attempt a parseFloat and fallback to a string if the parse fails
6187                         // so, simple values such as "10px" are parsed to Float.
6188                         // complex values such as "rotate(1rad)" are returned as is.
6189                         result = jQuery.css( tween.elem, tween.prop, "" );
6190                         // Empty strings, null, undefined and "auto" are converted to 0.
6191                         return !result || result === "auto" ? 0 : result;
6192                 },
6193                 set: function( tween ) {
6194                         // use step hook for back compat - use cssHook if its there - use .style if its
6195                         // available and use plain properties where available
6196                         if ( jQuery.fx.step[ tween.prop ] ) {
6197                                 jQuery.fx.step[ tween.prop ]( tween );
6198                         } else if ( tween.elem.style && ( tween.elem.style[ jQuery.cssProps[ tween.prop ] ] != null || jQuery.cssHooks[ tween.prop ] ) ) {
6199                                 jQuery.style( tween.elem, tween.prop, tween.now + tween.unit );
6200                         } else {
6201                                 tween.elem[ tween.prop ] = tween.now;
6202                         }
6203                 }
6204         }
6205 };
6206
6207 // Support: IE9
6208 // Panic based approach to setting things on disconnected nodes
6209
6210 Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = {
6211         set: function( tween ) {
6212                 if ( tween.elem.nodeType && tween.elem.parentNode ) {
6213                         tween.elem[ tween.prop ] = tween.now;
6214                 }
6215         }
6216 };
6217
6218 jQuery.easing = {
6219         linear: function( p ) {
6220                 return p;
6221         },
6222         swing: function( p ) {
6223                 return 0.5 - Math.cos( p * Math.PI ) / 2;
6224         }
6225 };
6226
6227 jQuery.fx = Tween.prototype.init;
6228
6229 // Back Compat <1.8 extension point
6230 jQuery.fx.step = {};
6231
6232
6233
6234
6235 var
6236         fxNow, timerId,
6237         rfxtypes = /^(?:toggle|show|hide)$/,
6238         rfxnum = new RegExp( "^(?:([+-])=|)(" + pnum + ")([a-z%]*)$", "i" ),
6239         rrun = /queueHooks$/,
6240         animationPrefilters = [ defaultPrefilter ],
6241         tweeners = {
6242                 "*": [ function( prop, value ) {
6243                         var tween = this.createTween( prop, value ),
6244                                 target = tween.cur(),
6245                                 parts = rfxnum.exec( value ),
6246                                 unit = parts && parts[ 3 ] || ( jQuery.cssNumber[ prop ] ? "" : "px" ),
6247
6248                                 // Starting value computation is required for potential unit mismatches
6249                                 start = ( jQuery.cssNumber[ prop ] || unit !== "px" && +target ) &&
6250                                         rfxnum.exec( jQuery.css( tween.elem, prop ) ),
6251                                 scale = 1,
6252                                 maxIterations = 20;
6253
6254                         if ( start && start[ 3 ] !== unit ) {
6255                                 // Trust units reported by jQuery.css
6256                                 unit = unit || start[ 3 ];
6257
6258                                 // Make sure we update the tween properties later on
6259                                 parts = parts || [];
6260
6261                                 // Iteratively approximate from a nonzero starting point
6262                                 start = +target || 1;
6263
6264                                 do {
6265                                         // If previous iteration zeroed out, double until we get *something*
6266                                         // Use a string for doubling factor so we don't accidentally see scale as unchanged below
6267                                         scale = scale || ".5";
6268
6269                                         // Adjust and apply
6270                                         start = start / scale;
6271                                         jQuery.style( tween.elem, prop, start + unit );
6272
6273                                 // Update scale, tolerating zero or NaN from tween.cur()
6274                                 // And breaking the loop if scale is unchanged or perfect, or if we've just had enough
6275                                 } while ( scale !== (scale = tween.cur() / target) && scale !== 1 && --maxIterations );
6276                         }
6277
6278                         // Update tween properties
6279                         if ( parts ) {
6280                                 start = tween.start = +start || +target || 0;
6281                                 tween.unit = unit;
6282                                 // If a +=/-= token was provided, we're doing a relative animation
6283                                 tween.end = parts[ 1 ] ?
6284                                         start + ( parts[ 1 ] + 1 ) * parts[ 2 ] :
6285                                         +parts[ 2 ];
6286                         }
6287
6288                         return tween;
6289                 } ]
6290         };
6291
6292 // Animations created synchronously will run synchronously
6293 function createFxNow() {
6294         setTimeout(function() {
6295                 fxNow = undefined;
6296         });
6297         return ( fxNow = jQuery.now() );
6298 }
6299
6300 // Generate parameters to create a standard animation
6301 function genFx( type, includeWidth ) {
6302         var which,
6303                 i = 0,
6304                 attrs = { height: type };
6305
6306         // if we include width, step value is 1 to do all cssExpand values,
6307         // if we don't include width, step value is 2 to skip over Left and Right
6308         includeWidth = includeWidth ? 1 : 0;
6309         for ( ; i < 4 ; i += 2 - includeWidth ) {
6310                 which = cssExpand[ i ];
6311                 attrs[ "margin" + which ] = attrs[ "padding" + which ] = type;
6312         }
6313
6314         if ( includeWidth ) {
6315                 attrs.opacity = attrs.width = type;
6316         }
6317
6318         return attrs;
6319 }
6320
6321 function createTween( value, prop, animation ) {
6322         var tween,
6323                 collection = ( tweeners[ prop ] || [] ).concat( tweeners[ "*" ] ),
6324                 index = 0,
6325                 length = collection.length;
6326         for ( ; index < length; index++ ) {
6327                 if ( (tween = collection[ index ].call( animation, prop, value )) ) {
6328
6329                         // we're done with this property
6330                         return tween;
6331                 }
6332         }
6333 }
6334
6335 function defaultPrefilter( elem, props, opts ) {
6336         /* jshint validthis: true */
6337         var prop, value, toggle, tween, hooks, oldfire, display, checkDisplay,
6338                 anim = this,
6339                 orig = {},
6340                 style = elem.style,
6341                 hidden = elem.nodeType && isHidden( elem ),
6342                 dataShow = data_priv.get( elem, "fxshow" );
6343
6344         // handle queue: false promises
6345         if ( !opts.queue ) {
6346                 hooks = jQuery._queueHooks( elem, "fx" );
6347                 if ( hooks.unqueued == null ) {
6348                         hooks.unqueued = 0;
6349                         oldfire = hooks.empty.fire;
6350                         hooks.empty.fire = function() {
6351                                 if ( !hooks.unqueued ) {
6352                                         oldfire();
6353                                 }
6354                         };
6355                 }
6356                 hooks.unqueued++;
6357
6358                 anim.always(function() {
6359                         // doing this makes sure that the complete handler will be called
6360                         // before this completes
6361                         anim.always(function() {
6362                                 hooks.unqueued--;
6363                                 if ( !jQuery.queue( elem, "fx" ).length ) {
6364                                         hooks.empty.fire();
6365                                 }
6366                         });
6367                 });
6368         }
6369
6370         // height/width overflow pass
6371         if ( elem.nodeType === 1 && ( "height" in props || "width" in props ) ) {
6372                 // Make sure that nothing sneaks out
6373                 // Record all 3 overflow attributes because IE9-10 do not
6374                 // change the overflow attribute when overflowX and
6375                 // overflowY are set to the same value
6376                 opts.overflow = [ style.overflow, style.overflowX, style.overflowY ];
6377
6378                 // Set display property to inline-block for height/width
6379                 // animations on inline elements that are having width/height animated
6380                 display = jQuery.css( elem, "display" );
6381
6382                 // Test default display if display is currently "none"
6383                 checkDisplay = display === "none" ?
6384                         data_priv.get( elem, "olddisplay" ) || defaultDisplay( elem.nodeName ) : display;
6385
6386                 if ( checkDisplay === "inline" && jQuery.css( elem, "float" ) === "none" ) {
6387                         style.display = "inline-block";
6388                 }
6389         }
6390
6391         if ( opts.overflow ) {
6392                 style.overflow = "hidden";
6393                 anim.always(function() {
6394                         style.overflow = opts.overflow[ 0 ];
6395                         style.overflowX = opts.overflow[ 1 ];
6396                         style.overflowY = opts.overflow[ 2 ];
6397                 });
6398         }
6399
6400         // show/hide pass
6401         for ( prop in props ) {
6402                 value = props[ prop ];
6403                 if ( rfxtypes.exec( value ) ) {
6404                         delete props[ prop ];
6405                         toggle = toggle || value === "toggle";
6406                         if ( value === ( hidden ? "hide" : "show" ) ) {
6407
6408                                 // If there is dataShow left over from a stopped hide or show and we are going to proceed with show, we should pretend to be hidden
6409                                 if ( value === "show" && dataShow && dataShow[ prop ] !== undefined ) {
6410                                         hidden = true;
6411                                 } else {
6412                                         continue;
6413                                 }
6414                         }
6415                         orig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop );
6416
6417                 // Any non-fx value stops us from restoring the original display value
6418                 } else {
6419                         display = undefined;
6420                 }
6421         }
6422
6423         if ( !jQuery.isEmptyObject( orig ) ) {
6424                 if ( dataShow ) {
6425                         if ( "hidden" in dataShow ) {
6426                                 hidden = dataShow.hidden;
6427                         }
6428                 } else {
6429                         dataShow = data_priv.access( elem, "fxshow", {} );
6430                 }
6431
6432                 // store state if its toggle - enables .stop().toggle() to "reverse"
6433                 if ( toggle ) {
6434                         dataShow.hidden = !hidden;
6435                 }
6436                 if ( hidden ) {
6437                         jQuery( elem ).show();
6438                 } else {
6439                         anim.done(function() {
6440                                 jQuery( elem ).hide();
6441                         });
6442                 }
6443                 anim.done(function() {
6444                         var prop;
6445
6446                         data_priv.remove( elem, "fxshow" );
6447                         for ( prop in orig ) {
6448                                 jQuery.style( elem, prop, orig[ prop ] );
6449                         }
6450                 });
6451                 for ( prop in orig ) {
6452                         tween = createTween( hidden ? dataShow[ prop ] : 0, prop, anim );
6453
6454                         if ( !( prop in dataShow ) ) {
6455                                 dataShow[ prop ] = tween.start;
6456                                 if ( hidden ) {
6457                                         tween.end = tween.start;
6458                                         tween.start = prop === "width" || prop === "height" ? 1 : 0;
6459                                 }
6460                         }
6461                 }
6462
6463         // If this is a noop like .hide().hide(), restore an overwritten display value
6464         } else if ( (display === "none" ? defaultDisplay( elem.nodeName ) : display) === "inline" ) {
6465                 style.display = display;
6466         }
6467 }
6468
6469 function propFilter( props, specialEasing ) {
6470         var index, name, easing, value, hooks;
6471
6472         // camelCase, specialEasing and expand cssHook pass
6473         for ( index in props ) {
6474                 name = jQuery.camelCase( index );
6475                 easing = specialEasing[ name ];
6476                 value = props[ index ];
6477                 if ( jQuery.isArray( value ) ) {
6478                         easing = value[ 1 ];
6479                         value = props[ index ] = value[ 0 ];
6480                 }
6481
6482                 if ( index !== name ) {
6483                         props[ name ] = value;
6484                         delete props[ index ];
6485                 }
6486
6487                 hooks = jQuery.cssHooks[ name ];
6488                 if ( hooks && "expand" in hooks ) {
6489                         value = hooks.expand( value );
6490                         delete props[ name ];
6491
6492                         // not quite $.extend, this wont overwrite keys already present.
6493                         // also - reusing 'index' from above because we have the correct "name"
6494                         for ( index in value ) {
6495                                 if ( !( index in props ) ) {
6496                                         props[ index ] = value[ index ];
6497                                         specialEasing[ index ] = easing;
6498                                 }
6499                         }
6500                 } else {
6501                         specialEasing[ name ] = easing;
6502                 }
6503         }
6504 }
6505
6506 function Animation( elem, properties, options ) {
6507         var result,
6508                 stopped,
6509                 index = 0,
6510                 length = animationPrefilters.length,
6511                 deferred = jQuery.Deferred().always( function() {
6512                         // don't match elem in the :animated selector
6513                         delete tick.elem;
6514                 }),
6515                 tick = function() {
6516                         if ( stopped ) {
6517                                 return false;
6518                         }
6519                         var currentTime = fxNow || createFxNow(),
6520                                 remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ),
6521                                 // archaic crash bug won't allow us to use 1 - ( 0.5 || 0 ) (#12497)
6522                                 temp = remaining / animation.duration || 0,
6523                                 percent = 1 - temp,
6524                                 index = 0,
6525                                 length = animation.tweens.length;
6526
6527                         for ( ; index < length ; index++ ) {
6528                                 animation.tweens[ index ].run( percent );
6529                         }
6530
6531                         deferred.notifyWith( elem, [ animation, percent, remaining ]);
6532
6533                         if ( percent < 1 && length ) {
6534                                 return remaining;
6535                         } else {
6536                                 deferred.resolveWith( elem, [ animation ] );
6537                                 return false;
6538                         }
6539                 },
6540                 animation = deferred.promise({
6541                         elem: elem,
6542                         props: jQuery.extend( {}, properties ),
6543                         opts: jQuery.extend( true, { specialEasing: {} }, options ),
6544                         originalProperties: properties,
6545                         originalOptions: options,
6546                         startTime: fxNow || createFxNow(),
6547                         duration: options.duration,
6548                         tweens: [],
6549                         createTween: function( prop, end ) {
6550                                 var tween = jQuery.Tween( elem, animation.opts, prop, end,
6551                                                 animation.opts.specialEasing[ prop ] || animation.opts.easing );
6552                                 animation.tweens.push( tween );
6553                                 return tween;
6554                         },
6555                         stop: function( gotoEnd ) {
6556                                 var index = 0,
6557                                         // if we are going to the end, we want to run all the tweens
6558                                         // otherwise we skip this part
6559                                         length = gotoEnd ? animation.tweens.length : 0;
6560                                 if ( stopped ) {
6561                                         return this;
6562                                 }
6563                                 stopped = true;
6564                                 for ( ; index < length ; index++ ) {
6565                                         animation.tweens[ index ].run( 1 );
6566                                 }
6567
6568                                 // resolve when we played the last frame
6569                                 // otherwise, reject
6570                                 if ( gotoEnd ) {
6571                                         deferred.resolveWith( elem, [ animation, gotoEnd ] );
6572                                 } else {
6573                                         deferred.rejectWith( elem, [ animation, gotoEnd ] );
6574                                 }
6575                                 return this;
6576                         }
6577                 }),
6578                 props = animation.props;
6579
6580         propFilter( props, animation.opts.specialEasing );
6581
6582         for ( ; index < length ; index++ ) {
6583                 result = animationPrefilters[ index ].call( animation, elem, props, animation.opts );
6584                 if ( result ) {
6585                         return result;
6586                 }
6587         }
6588
6589         jQuery.map( props, createTween, animation );
6590
6591         if ( jQuery.isFunction( animation.opts.start ) ) {
6592                 animation.opts.start.call( elem, animation );
6593         }
6594
6595         jQuery.fx.timer(
6596                 jQuery.extend( tick, {
6597                         elem: elem,
6598                         anim: animation,
6599                         queue: animation.opts.queue
6600                 })
6601         );
6602
6603         // attach callbacks from options
6604         return animation.progress( animation.opts.progress )
6605                 .done( animation.opts.done, animation.opts.complete )
6606                 .fail( animation.opts.fail )
6607                 .always( animation.opts.always );
6608 }
6609
6610 jQuery.Animation = jQuery.extend( Animation, {
6611
6612         tweener: function( props, callback ) {
6613                 if ( jQuery.isFunction( props ) ) {
6614                         callback = props;
6615                         props = [ "*" ];
6616                 } else {
6617                         props = props.split(" ");
6618                 }
6619
6620                 var prop,
6621                         index = 0,
6622                         length = props.length;
6623
6624                 for ( ; index < length ; index++ ) {
6625                         prop = props[ index ];
6626                         tweeners[ prop ] = tweeners[ prop ] || [];
6627                         tweeners[ prop ].unshift( callback );
6628                 }
6629         },
6630
6631         prefilter: function( callback, prepend ) {
6632                 if ( prepend ) {
6633                         animationPrefilters.unshift( callback );
6634                 } else {
6635                         animationPrefilters.push( callback );
6636                 }
6637         }
6638 });
6639
6640 jQuery.speed = function( speed, easing, fn ) {
6641         var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : {
6642                 complete: fn || !fn && easing ||
6643                         jQuery.isFunction( speed ) && speed,
6644                 duration: speed,
6645                 easing: fn && easing || easing && !jQuery.isFunction( easing ) && easing
6646         };
6647
6648         opt.duration = jQuery.fx.off ? 0 : typeof opt.duration === "number" ? opt.duration :
6649                 opt.duration in jQuery.fx.speeds ? jQuery.fx.speeds[ opt.duration ] : jQuery.fx.speeds._default;
6650
6651         // normalize opt.queue - true/undefined/null -> "fx"
6652         if ( opt.queue == null || opt.queue === true ) {
6653                 opt.queue = "fx";
6654         }
6655
6656         // Queueing
6657         opt.old = opt.complete;
6658
6659         opt.complete = function() {
6660                 if ( jQuery.isFunction( opt.old ) ) {
6661                         opt.old.call( this );
6662                 }
6663
6664                 if ( opt.queue ) {
6665                         jQuery.dequeue( this, opt.queue );
6666                 }
6667         };
6668
6669         return opt;
6670 };
6671
6672 jQuery.fn.extend({
6673         fadeTo: function( speed, to, easing, callback ) {
6674
6675                 // show any hidden elements after setting opacity to 0
6676                 return this.filter( isHidden ).css( "opacity", 0 ).show()
6677
6678                         // animate to the value specified
6679                         .end().animate({ opacity: to }, speed, easing, callback );
6680         },
6681         animate: function( prop, speed, easing, callback ) {
6682                 var empty = jQuery.isEmptyObject( prop ),
6683                         optall = jQuery.speed( speed, easing, callback ),
6684                         doAnimation = function() {
6685                                 // Operate on a copy of prop so per-property easing won't be lost
6686                                 var anim = Animation( this, jQuery.extend( {}, prop ), optall );
6687
6688                                 // Empty animations, or finishing resolves immediately
6689                                 if ( empty || data_priv.get( this, "finish" ) ) {
6690                                         anim.stop( true );
6691                                 }
6692                         };
6693                         doAnimation.finish = doAnimation;
6694
6695                 return empty || optall.queue === false ?
6696                         this.each( doAnimation ) :
6697                         this.queue( optall.queue, doAnimation );
6698         },
6699         stop: function( type, clearQueue, gotoEnd ) {
6700                 var stopQueue = function( hooks ) {
6701                         var stop = hooks.stop;
6702                         delete hooks.stop;
6703                         stop( gotoEnd );
6704                 };
6705
6706                 if ( typeof type !== "string" ) {
6707                         gotoEnd = clearQueue;
6708                         clearQueue = type;
6709                         type = undefined;
6710                 }
6711                 if ( clearQueue && type !== false ) {
6712                         this.queue( type || "fx", [] );
6713                 }
6714
6715                 return this.each(function() {
6716                         var dequeue = true,
6717                                 index = type != null && type + "queueHooks",
6718                                 timers = jQuery.timers,
6719                                 data = data_priv.get( this );
6720
6721                         if ( index ) {
6722                                 if ( data[ index ] && data[ index ].stop ) {
6723                                         stopQueue( data[ index ] );
6724                                 }
6725                         } else {
6726                                 for ( index in data ) {
6727                                         if ( data[ index ] && data[ index ].stop && rrun.test( index ) ) {
6728                                                 stopQueue( data[ index ] );
6729                                         }
6730                                 }
6731                         }
6732
6733                         for ( index = timers.length; index--; ) {
6734                                 if ( timers[ index ].elem === this && (type == null || timers[ index ].queue === type) ) {
6735                                         timers[ index ].anim.stop( gotoEnd );
6736                                         dequeue = false;
6737                                         timers.splice( index, 1 );
6738                                 }
6739                         }
6740
6741                         // start the next in the queue if the last step wasn't forced
6742                         // timers currently will call their complete callbacks, which will dequeue
6743                         // but only if they were gotoEnd
6744                         if ( dequeue || !gotoEnd ) {
6745                                 jQuery.dequeue( this, type );
6746                         }
6747                 });
6748         },
6749         finish: function( type ) {
6750                 if ( type !== false ) {
6751                         type = type || "fx";
6752                 }
6753                 return this.each(function() {
6754                         var index,
6755                                 data = data_priv.get( this ),
6756                                 queue = data[ type + "queue" ],
6757                                 hooks = data[ type + "queueHooks" ],
6758                                 timers = jQuery.timers,
6759                                 length = queue ? queue.length : 0;
6760
6761                         // enable finishing flag on private data
6762                         data.finish = true;
6763
6764                         // empty the queue first
6765                         jQuery.queue( this, type, [] );
6766
6767                         if ( hooks && hooks.stop ) {
6768                                 hooks.stop.call( this, true );
6769                         }
6770
6771                         // look for any active animations, and finish them
6772                         for ( index = timers.length; index--; ) {
6773                                 if ( timers[ index ].elem === this && timers[ index ].queue === type ) {
6774                                         timers[ index ].anim.stop( true );
6775                                         timers.splice( index, 1 );
6776                                 }
6777                         }
6778
6779                         // look for any animations in the old queue and finish them
6780                         for ( index = 0; index < length; index++ ) {
6781                                 if ( queue[ index ] && queue[ index ].finish ) {
6782                                         queue[ index ].finish.call( this );
6783                                 }
6784                         }
6785
6786                         // turn off finishing flag
6787                         delete data.finish;
6788                 });
6789         }
6790 });
6791
6792 jQuery.each([ "toggle", "show", "hide" ], function( i, name ) {
6793         var cssFn = jQuery.fn[ name ];
6794         jQuery.fn[ name ] = function( speed, easing, callback ) {
6795                 return speed == null || typeof speed === "boolean" ?
6796                         cssFn.apply( this, arguments ) :
6797                         this.animate( genFx( name, true ), speed, easing, callback );
6798         };
6799 });
6800
6801 // Generate shortcuts for custom animations
6802 jQuery.each({
6803         slideDown: genFx("show"),
6804         slideUp: genFx("hide"),
6805         slideToggle: genFx("toggle"),
6806         fadeIn: { opacity: "show" },
6807         fadeOut: { opacity: "hide" },
6808         fadeToggle: { opacity: "toggle" }
6809 }, function( name, props ) {
6810         jQuery.fn[ name ] = function( speed, easing, callback ) {
6811                 return this.animate( props, speed, easing, callback );
6812         };
6813 });
6814
6815 jQuery.timers = [];
6816 jQuery.fx.tick = function() {
6817         var timer,
6818                 i = 0,
6819                 timers = jQuery.timers;
6820
6821         fxNow = jQuery.now();
6822
6823         for ( ; i < timers.length; i++ ) {
6824                 timer = timers[ i ];
6825                 // Checks the timer has not already been removed
6826                 if ( !timer() && timers[ i ] === timer ) {
6827                         timers.splice( i--, 1 );
6828                 }
6829         }
6830
6831         if ( !timers.length ) {
6832                 jQuery.fx.stop();
6833         }
6834         fxNow = undefined;
6835 };
6836
6837 jQuery.fx.timer = function( timer ) {
6838         jQuery.timers.push( timer );
6839         if ( timer() ) {
6840                 jQuery.fx.start();
6841         } else {
6842                 jQuery.timers.pop();
6843         }
6844 };
6845
6846 jQuery.fx.interval = 13;
6847
6848 jQuery.fx.start = function() {
6849         if ( !timerId ) {
6850                 timerId = setInterval( jQuery.fx.tick, jQuery.fx.interval );
6851         }
6852 };
6853
6854 jQuery.fx.stop = function() {
6855         clearInterval( timerId );
6856         timerId = null;
6857 };
6858
6859 jQuery.fx.speeds = {
6860         slow: 600,
6861         fast: 200,
6862         // Default speed
6863         _default: 400
6864 };
6865
6866
6867 // Based off of the plugin by Clint Helfers, with permission.
6868 // http://blindsignals.com/index.php/2009/07/jquery-delay/
6869 jQuery.fn.delay = function( time, type ) {
6870         time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time;
6871         type = type || "fx";
6872
6873         return this.queue( type, function( next, hooks ) {
6874                 var timeout = setTimeout( next, time );
6875                 hooks.stop = function() {
6876                         clearTimeout( timeout );
6877                 };
6878         });
6879 };
6880
6881
6882 (function() {
6883         var input = document.createElement( "input" ),
6884                 select = document.createElement( "select" ),
6885                 opt = select.appendChild( document.createElement( "option" ) );
6886
6887         input.type = "checkbox";
6888
6889         // Support: iOS 5.1, Android 4.x, Android 2.3
6890         // Check the default checkbox/radio value ("" on old WebKit; "on" elsewhere)
6891         support.checkOn = input.value !== "";
6892
6893         // Must access the parent to make an option select properly
6894         // Support: IE9, IE10
6895         support.optSelected = opt.selected;
6896
6897         // Make sure that the options inside disabled selects aren't marked as disabled
6898         // (WebKit marks them as disabled)
6899         select.disabled = true;
6900         support.optDisabled = !opt.disabled;
6901
6902         // Check if an input maintains its value after becoming a radio
6903         // Support: IE9, IE10
6904         input = document.createElement( "input" );
6905         input.value = "t";
6906         input.type = "radio";
6907         support.radioValue = input.value === "t";
6908 })();
6909
6910
6911 var nodeHook, boolHook,
6912         attrHandle = jQuery.expr.attrHandle;
6913
6914 jQuery.fn.extend({
6915         attr: function( name, value ) {
6916                 return access( this, jQuery.attr, name, value, arguments.length > 1 );
6917         },
6918
6919         removeAttr: function( name ) {
6920                 return this.each(function() {
6921                         jQuery.removeAttr( this, name );
6922                 });
6923         }
6924 });
6925
6926 jQuery.extend({
6927         attr: function( elem, name, value ) {
6928                 var hooks, ret,
6929                         nType = elem.nodeType;
6930
6931                 // don't get/set attributes on text, comment and attribute nodes
6932                 if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
6933                         return;
6934                 }
6935
6936                 // Fallback to prop when attributes are not supported
6937                 if ( typeof elem.getAttribute === strundefined ) {
6938                         return jQuery.prop( elem, name, value );
6939                 }
6940
6941                 // All attributes are lowercase
6942                 // Grab necessary hook if one is defined
6943                 if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) {
6944                         name = name.toLowerCase();
6945                         hooks = jQuery.attrHooks[ name ] ||
6946                                 ( jQuery.expr.match.bool.test( name ) ? boolHook : nodeHook );
6947                 }
6948
6949                 if ( value !== undefined ) {
6950
6951                         if ( value === null ) {
6952                                 jQuery.removeAttr( elem, name );
6953
6954                         } else if ( hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ) {
6955                                 return ret;
6956
6957                         } else {
6958                                 elem.setAttribute( name, value + "" );
6959                                 return value;
6960                         }
6961
6962                 } else if ( hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ) {
6963                         return ret;
6964
6965                 } else {
6966                         ret = jQuery.find.attr( elem, name );
6967
6968                         // Non-existent attributes return null, we normalize to undefined
6969                         return ret == null ?
6970                                 undefined :
6971                                 ret;
6972                 }
6973         },
6974
6975         removeAttr: function( elem, value ) {
6976                 var name, propName,
6977                         i = 0,
6978                         attrNames = value && value.match( rnotwhite );
6979
6980                 if ( attrNames && elem.nodeType === 1 ) {
6981                         while ( (name = attrNames[i++]) ) {
6982                                 propName = jQuery.propFix[ name ] || name;
6983
6984                                 // Boolean attributes get special treatment (#10870)
6985                                 if ( jQuery.expr.match.bool.test( name ) ) {
6986                                         // Set corresponding property to false
6987                                         elem[ propName ] = false;
6988                                 }
6989
6990                                 elem.removeAttribute( name );
6991                         }
6992                 }
6993         },
6994
6995         attrHooks: {
6996                 type: {
6997                         set: function( elem, value ) {
6998                                 if ( !support.radioValue && value === "radio" &&
6999                                         jQuery.nodeName( elem, "input" ) ) {
7000                                         // Setting the type on a radio button after the value resets the value in IE6-9
7001                                         // Reset value to default in case type is set after value during creation
7002                                         var val = elem.value;
7003                                         elem.setAttribute( "type", value );
7004                                         if ( val ) {
7005                                                 elem.value = val;
7006                                         }
7007                                         return value;
7008                                 }
7009                         }
7010                 }
7011         }
7012 });
7013
7014 // Hooks for boolean attributes
7015 boolHook = {
7016         set: function( elem, value, name ) {
7017                 if ( value === false ) {
7018                         // Remove boolean attributes when set to false
7019                         jQuery.removeAttr( elem, name );
7020                 } else {
7021                         elem.setAttribute( name, name );
7022                 }
7023                 return name;
7024         }
7025 };
7026 jQuery.each( jQuery.expr.match.bool.source.match( /\w+/g ), function( i, name ) {
7027         var getter = attrHandle[ name ] || jQuery.find.attr;
7028
7029         attrHandle[ name ] = function( elem, name, isXML ) {
7030                 var ret, handle;
7031                 if ( !isXML ) {
7032                         // Avoid an infinite loop by temporarily removing this function from the getter
7033                         handle = attrHandle[ name ];
7034                         attrHandle[ name ] = ret;
7035                         ret = getter( elem, name, isXML ) != null ?
7036                                 name.toLowerCase() :
7037                                 null;
7038                         attrHandle[ name ] = handle;
7039                 }
7040                 return ret;
7041         };
7042 });
7043
7044
7045
7046
7047 var rfocusable = /^(?:input|select|textarea|button)$/i;
7048
7049 jQuery.fn.extend({
7050         prop: function( name, value ) {
7051                 return access( this, jQuery.prop, name, value, arguments.length > 1 );
7052         },
7053
7054         removeProp: function( name ) {
7055                 return this.each(function() {
7056                         delete this[ jQuery.propFix[ name ] || name ];
7057                 });
7058         }
7059 });
7060
7061 jQuery.extend({
7062         propFix: {
7063                 "for": "htmlFor",
7064                 "class": "className"
7065         },
7066
7067         prop: function( elem, name, value ) {
7068                 var ret, hooks, notxml,
7069                         nType = elem.nodeType;
7070
7071                 // don't get/set properties on text, comment and attribute nodes
7072                 if ( !elem || nType === 3 || nType === 8 || nType === 2 ) {
7073                         return;
7074                 }
7075
7076                 notxml = nType !== 1 || !jQuery.isXMLDoc( elem );
7077
7078                 if ( notxml ) {
7079                         // Fix name and attach hooks
7080                         name = jQuery.propFix[ name ] || name;
7081                         hooks = jQuery.propHooks[ name ];
7082                 }
7083
7084                 if ( value !== undefined ) {
7085                         return hooks && "set" in hooks && (ret = hooks.set( elem, value, name )) !== undefined ?
7086                                 ret :
7087                                 ( elem[ name ] = value );
7088
7089                 } else {
7090                         return hooks && "get" in hooks && (ret = hooks.get( elem, name )) !== null ?
7091                                 ret :
7092                                 elem[ name ];
7093                 }
7094         },
7095
7096         propHooks: {
7097                 tabIndex: {
7098                         get: function( elem ) {
7099                                 return elem.hasAttribute( "tabindex" ) || rfocusable.test( elem.nodeName ) || elem.href ?
7100                                         elem.tabIndex :
7101                                         -1;
7102                         }
7103                 }
7104         }
7105 });
7106
7107 // Support: IE9+
7108 // Selectedness for an option in an optgroup can be inaccurate
7109 if ( !support.optSelected ) {
7110         jQuery.propHooks.selected = {
7111                 get: function( elem ) {
7112                         var parent = elem.parentNode;
7113                         if ( parent && parent.parentNode ) {
7114                                 parent.parentNode.selectedIndex;
7115                         }
7116                         return null;
7117                 }
7118         };
7119 }
7120
7121 jQuery.each([
7122         "tabIndex",
7123         "readOnly",
7124         "maxLength",
7125         "cellSpacing",
7126         "cellPadding",
7127         "rowSpan",
7128         "colSpan",
7129         "useMap",
7130         "frameBorder",
7131         "contentEditable"
7132 ], function() {
7133         jQuery.propFix[ this.toLowerCase() ] = this;
7134 });
7135
7136
7137
7138
7139 var rclass = /[\t\r\n\f]/g;
7140
7141 jQuery.fn.extend({
7142         addClass: function( value ) {
7143                 var classes, elem, cur, clazz, j, finalValue,
7144                         proceed = typeof value === "string" && value,
7145                         i = 0,
7146                         len = this.length;
7147
7148                 if ( jQuery.isFunction( value ) ) {
7149                         return this.each(function( j ) {
7150                                 jQuery( this ).addClass( value.call( this, j, this.className ) );
7151                         });
7152                 }
7153
7154                 if ( proceed ) {
7155                         // The disjunction here is for better compressibility (see removeClass)
7156                         classes = ( value || "" ).match( rnotwhite ) || [];
7157
7158                         for ( ; i < len; i++ ) {
7159                                 elem = this[ i ];
7160                                 cur = elem.nodeType === 1 && ( elem.className ?
7161                                         ( " " + elem.className + " " ).replace( rclass, " " ) :
7162                                         " "
7163                                 );
7164
7165                                 if ( cur ) {
7166                                         j = 0;
7167                                         while ( (clazz = classes[j++]) ) {
7168                                                 if ( cur.indexOf( " " + clazz + " " ) < 0 ) {
7169                                                         cur += clazz + " ";
7170                                                 }
7171                                         }
7172
7173                                         // only assign if different to avoid unneeded rendering.
7174                                         finalValue = jQuery.trim( cur );
7175                                         if ( elem.className !== finalValue ) {
7176                                                 elem.className = finalValue;
7177                                         }
7178                                 }
7179                         }
7180                 }
7181
7182                 return this;
7183         },
7184
7185         removeClass: function( value ) {
7186                 var classes, elem, cur, clazz, j, finalValue,
7187                         proceed = arguments.length === 0 || typeof value === "string" && value,
7188                         i = 0,
7189                         len = this.length;
7190
7191                 if ( jQuery.isFunction( value ) ) {
7192                         return this.each(function( j ) {
7193                                 jQuery( this ).removeClass( value.call( this, j, this.className ) );
7194                         });
7195                 }
7196                 if ( proceed ) {
7197                         classes = ( value || "" ).match( rnotwhite ) || [];
7198
7199                         for ( ; i < len; i++ ) {
7200                                 elem = this[ i ];
7201                                 // This expression is here for better compressibility (see addClass)
7202                                 cur = elem.nodeType === 1 && ( elem.className ?
7203                                         ( " " + elem.className + " " ).replace( rclass, " " ) :
7204                                         ""
7205                                 );
7206
7207                                 if ( cur ) {
7208                                         j = 0;
7209                                         while ( (clazz = classes[j++]) ) {
7210                                                 // Remove *all* instances
7211                                                 while ( cur.indexOf( " " + clazz + " " ) >= 0 ) {
7212                                                         cur = cur.replace( " " + clazz + " ", " " );
7213                                                 }
7214                                         }
7215
7216                                         // only assign if different to avoid unneeded rendering.
7217                                         finalValue = value ? jQuery.trim( cur ) : "";
7218                                         if ( elem.className !== finalValue ) {
7219                                                 elem.className = finalValue;
7220                                         }
7221                                 }
7222                         }
7223                 }
7224
7225                 return this;
7226         },
7227
7228         toggleClass: function( value, stateVal ) {
7229                 var type = typeof value;
7230
7231                 if ( typeof stateVal === "boolean" && type === "string" ) {
7232                         return stateVal ? this.addClass( value ) : this.removeClass( value );
7233                 }
7234
7235                 if ( jQuery.isFunction( value ) ) {
7236                         return this.each(function( i ) {
7237                                 jQuery( this ).toggleClass( value.call(this, i, this.className, stateVal), stateVal );
7238                         });
7239                 }
7240
7241                 return this.each(function() {
7242                         if ( type === "string" ) {
7243                                 // toggle individual class names
7244                                 var className,
7245                                         i = 0,
7246                                         self = jQuery( this ),
7247                                         classNames = value.match( rnotwhite ) || [];
7248
7249                                 while ( (className = classNames[ i++ ]) ) {
7250                                         // check each className given, space separated list
7251                                         if ( self.hasClass( className ) ) {
7252                                                 self.removeClass( className );
7253                                         } else {
7254                                                 self.addClass( className );
7255                                         }
7256                                 }
7257
7258                         // Toggle whole class name
7259                         } else if ( type === strundefined || type === "boolean" ) {
7260                                 if ( this.className ) {
7261                                         // store className if set
7262                                         data_priv.set( this, "__className__", this.className );
7263                                 }
7264
7265                                 // If the element has a class name or if we're passed "false",
7266                                 // then remove the whole classname (if there was one, the above saved it).
7267                                 // Otherwise bring back whatever was previously saved (if anything),
7268                                 // falling back to the empty string if nothing was stored.
7269                                 this.className = this.className || value === false ? "" : data_priv.get( this, "__className__" ) || "";
7270                         }
7271                 });
7272         },
7273
7274         hasClass: function( selector ) {
7275                 var className = " " + selector + " ",
7276                         i = 0,
7277                         l = this.length;
7278                 for ( ; i < l; i++ ) {
7279                         if ( this[i].nodeType === 1 && (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) >= 0 ) {
7280                                 return true;
7281                         }
7282                 }
7283
7284                 return false;
7285         }
7286 });
7287
7288
7289
7290
7291 var rreturn = /\r/g;
7292
7293 jQuery.fn.extend({
7294         val: function( value ) {
7295                 var hooks, ret, isFunction,
7296                         elem = this[0];
7297
7298                 if ( !arguments.length ) {
7299                         if ( elem ) {
7300                                 hooks = jQuery.valHooks[ elem.type ] || jQuery.valHooks[ elem.nodeName.toLowerCase() ];
7301
7302                                 if ( hooks && "get" in hooks && (ret = hooks.get( elem, "value" )) !== undefined ) {
7303                                         return ret;
7304                                 }
7305
7306                                 ret = elem.value;
7307
7308                                 return typeof ret === "string" ?
7309                                         // handle most common string cases
7310                                         ret.replace(rreturn, "") :
7311                                         // handle cases where value is null/undef or number
7312                                         ret == null ? "" : ret;
7313                         }
7314
7315                         return;
7316                 }
7317
7318                 isFunction = jQuery.isFunction( value );
7319
7320                 return this.each(function( i ) {
7321                         var val;
7322
7323                         if ( this.nodeType !== 1 ) {
7324                                 return;
7325                         }
7326
7327                         if ( isFunction ) {
7328                                 val = value.call( this, i, jQuery( this ).val() );
7329                         } else {
7330                                 val = value;
7331                         }
7332
7333                         // Treat null/undefined as ""; convert numbers to string
7334                         if ( val == null ) {
7335                                 val = "";
7336
7337                         } else if ( typeof val === "number" ) {
7338                                 val += "";
7339
7340                         } else if ( jQuery.isArray( val ) ) {
7341                                 val = jQuery.map( val, function( value ) {
7342                                         return value == null ? "" : value + "";
7343                                 });
7344                         }
7345
7346                         hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ];
7347
7348                         // If set returns undefined, fall back to normal setting
7349                         if ( !hooks || !("set" in hooks) || hooks.set( this, val, "value" ) === undefined ) {
7350                                 this.value = val;
7351                         }
7352                 });
7353         }
7354 });
7355
7356 jQuery.extend({
7357         valHooks: {
7358                 option: {
7359                         get: function( elem ) {
7360                                 var val = jQuery.find.attr( elem, "value" );
7361                                 return val != null ?
7362                                         val :
7363                                         // Support: IE10-11+
7364                                         // option.text throws exceptions (#14686, #14858)
7365                                         jQuery.trim( jQuery.text( elem ) );
7366                         }
7367                 },
7368                 select: {
7369                         get: function( elem ) {
7370                                 var value, option,
7371                                         options = elem.options,
7372                                         index = elem.selectedIndex,
7373                                         one = elem.type === "select-one" || index < 0,
7374                                         values = one ? null : [],
7375                                         max = one ? index + 1 : options.length,
7376                                         i = index < 0 ?
7377                                                 max :
7378                                                 one ? index : 0;
7379
7380                                 // Loop through all the selected options
7381                                 for ( ; i < max; i++ ) {
7382                                         option = options[ i ];
7383
7384                                         // IE6-9 doesn't update selected after form reset (#2551)
7385                                         if ( ( option.selected || i === index ) &&
7386                                                         // Don't return options that are disabled or in a disabled optgroup
7387                                                         ( support.optDisabled ? !option.disabled : option.getAttribute( "disabled" ) === null ) &&
7388                                                         ( !option.parentNode.disabled || !jQuery.nodeName( option.parentNode, "optgroup" ) ) ) {
7389
7390                                                 // Get the specific value for the option
7391                                                 value = jQuery( option ).val();
7392
7393                                                 // We don't need an array for one selects
7394                                                 if ( one ) {
7395                                                         return value;
7396                                                 }
7397
7398                                                 // Multi-Selects return an array
7399                                                 values.push( value );
7400                                         }
7401                                 }
7402
7403                                 return values;
7404                         },
7405
7406                         set: function( elem, value ) {
7407                                 var optionSet, option,
7408                                         options = elem.options,
7409                                         values = jQuery.makeArray( value ),
7410                                         i = options.length;
7411
7412                                 while ( i-- ) {
7413                                         option = options[ i ];
7414                                         if ( (option.selected = jQuery.inArray( option.value, values ) >= 0) ) {
7415                                                 optionSet = true;
7416                                         }
7417                                 }
7418
7419                                 // force browsers to behave consistently when non-matching value is set
7420                                 if ( !optionSet ) {
7421                                         elem.selectedIndex = -1;
7422                                 }
7423                                 return values;
7424                         }
7425                 }
7426         }
7427 });
7428
7429 // Radios and checkboxes getter/setter
7430 jQuery.each([ "radio", "checkbox" ], function() {
7431         jQuery.valHooks[ this ] = {
7432                 set: function( elem, value ) {
7433                         if ( jQuery.isArray( value ) ) {
7434                                 return ( elem.checked = jQuery.inArray( jQuery(elem).val(), value ) >= 0 );
7435                         }
7436                 }
7437         };
7438         if ( !support.checkOn ) {
7439                 jQuery.valHooks[ this ].get = function( elem ) {
7440                         // Support: Webkit
7441                         // "" is returned instead of "on" if a value isn't specified
7442                         return elem.getAttribute("value") === null ? "on" : elem.value;
7443                 };
7444         }
7445 });
7446
7447
7448
7449
7450 // Return jQuery for attributes-only inclusion
7451
7452
7453 jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " +
7454         "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " +
7455         "change select submit keydown keypress keyup error contextmenu").split(" "), function( i, name ) {
7456
7457         // Handle event binding
7458         jQuery.fn[ name ] = function( data, fn ) {
7459                 return arguments.length > 0 ?
7460                         this.on( name, null, data, fn ) :
7461                         this.trigger( name );
7462         };
7463 });
7464
7465 jQuery.fn.extend({
7466         hover: function( fnOver, fnOut ) {
7467                 return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );
7468         },
7469
7470         bind: function( types, data, fn ) {
7471                 return this.on( types, null, data, fn );
7472         },
7473         unbind: function( types, fn ) {
7474                 return this.off( types, null, fn );
7475         },
7476
7477         delegate: function( selector, types, data, fn ) {
7478                 return this.on( types, selector, data, fn );
7479         },
7480         undelegate: function( selector, types, fn ) {
7481                 // ( namespace ) or ( selector, types [, fn] )
7482                 return arguments.length === 1 ? this.off( selector, "**" ) : this.off( types, selector || "**", fn );
7483         }
7484 });
7485
7486
7487 var nonce = jQuery.now();
7488
7489 var rquery = (/\?/);
7490
7491
7492
7493 // Support: Android 2.3
7494 // Workaround failure to string-cast null input
7495 jQuery.parseJSON = function( data ) {
7496         return JSON.parse( data + "" );
7497 };
7498
7499
7500 // Cross-browser xml parsing
7501 jQuery.parseXML = function( data ) {
7502         var xml, tmp;
7503         if ( !data || typeof data !== "string" ) {
7504                 return null;
7505         }
7506
7507         // Support: IE9
7508         try {
7509                 tmp = new DOMParser();
7510                 xml = tmp.parseFromString( data, "text/xml" );
7511         } catch ( e ) {
7512                 xml = undefined;
7513         }
7514
7515         if ( !xml || xml.getElementsByTagName( "parsererror" ).length ) {
7516                 jQuery.error( "Invalid XML: " + data );
7517         }
7518         return xml;
7519 };
7520
7521
7522 var
7523         // Document location
7524         ajaxLocParts,
7525         ajaxLocation,
7526
7527         rhash = /#.*$/,
7528         rts = /([?&])_=[^&]*/,
7529         rheaders = /^(.*?):[ \t]*([^\r\n]*)$/mg,
7530         // #7653, #8125, #8152: local protocol detection
7531         rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/,
7532         rnoContent = /^(?:GET|HEAD)$/,
7533         rprotocol = /^\/\//,
7534         rurl = /^([\w.+-]+:)(?:\/\/(?:[^\/?#]*@|)([^\/?#:]*)(?::(\d+)|)|)/,
7535
7536         /* Prefilters
7537          * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example)
7538          * 2) These are called:
7539          *    - BEFORE asking for a transport
7540          *    - AFTER param serialization (s.data is a string if s.processData is true)
7541          * 3) key is the dataType
7542          * 4) the catchall symbol "*" can be used
7543          * 5) execution will start with transport dataType and THEN continue down to "*" if needed
7544          */
7545         prefilters = {},
7546
7547         /* Transports bindings
7548          * 1) key is the dataType
7549          * 2) the catchall symbol "*" can be used
7550          * 3) selection will start with transport dataType and THEN go to "*" if needed
7551          */
7552         transports = {},
7553
7554         // Avoid comment-prolog char sequence (#10098); must appease lint and evade compression
7555         allTypes = "*/".concat("*");
7556
7557 // #8138, IE may throw an exception when accessing
7558 // a field from window.location if document.domain has been set
7559 try {
7560         ajaxLocation = location.href;
7561 } catch( e ) {
7562         // Use the href attribute of an A element
7563         // since IE will modify it given document.location
7564         ajaxLocation = document.createElement( "a" );
7565         ajaxLocation.href = "";
7566         ajaxLocation = ajaxLocation.href;
7567 }
7568
7569 // Segment location into parts
7570 ajaxLocParts = rurl.exec( ajaxLocation.toLowerCase() ) || [];
7571
7572 // Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport
7573 function addToPrefiltersOrTransports( structure ) {
7574
7575         // dataTypeExpression is optional and defaults to "*"
7576         return function( dataTypeExpression, func ) {
7577
7578                 if ( typeof dataTypeExpression !== "string" ) {
7579                         func = dataTypeExpression;
7580                         dataTypeExpression = "*";
7581                 }
7582
7583                 var dataType,
7584                         i = 0,
7585                         dataTypes = dataTypeExpression.toLowerCase().match( rnotwhite ) || [];
7586
7587                 if ( jQuery.isFunction( func ) ) {
7588                         // For each dataType in the dataTypeExpression
7589                         while ( (dataType = dataTypes[i++]) ) {
7590                                 // Prepend if requested
7591                                 if ( dataType[0] === "+" ) {
7592                                         dataType = dataType.slice( 1 ) || "*";
7593                                         (structure[ dataType ] = structure[ dataType ] || []).unshift( func );
7594
7595                                 // Otherwise append
7596                                 } else {
7597                                         (structure[ dataType ] = structure[ dataType ] || []).push( func );
7598                                 }
7599                         }
7600                 }
7601         };
7602 }
7603
7604 // Base inspection function for prefilters and transports
7605 function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) {
7606
7607         var inspected = {},
7608                 seekingTransport = ( structure === transports );
7609
7610         function inspect( dataType ) {
7611                 var selected;
7612                 inspected[ dataType ] = true;
7613                 jQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) {
7614                         var dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR );
7615                         if ( typeof dataTypeOrTransport === "string" && !seekingTransport && !inspected[ dataTypeOrTransport ] ) {
7616                                 options.dataTypes.unshift( dataTypeOrTransport );
7617                                 inspect( dataTypeOrTransport );
7618                                 return false;
7619                         } else if ( seekingTransport ) {
7620                                 return !( selected = dataTypeOrTransport );
7621                         }
7622                 });
7623                 return selected;
7624         }
7625
7626         return inspect( options.dataTypes[ 0 ] ) || !inspected[ "*" ] && inspect( "*" );
7627 }
7628
7629 // A special extend for ajax options
7630 // that takes "flat" options (not to be deep extended)
7631 // Fixes #9887
7632 function ajaxExtend( target, src ) {
7633         var key, deep,
7634                 flatOptions = jQuery.ajaxSettings.flatOptions || {};
7635
7636         for ( key in src ) {
7637                 if ( src[ key ] !== undefined ) {
7638                         ( flatOptions[ key ] ? target : ( deep || (deep = {}) ) )[ key ] = src[ key ];
7639                 }
7640         }
7641         if ( deep ) {
7642                 jQuery.extend( true, target, deep );
7643         }
7644
7645         return target;
7646 }
7647
7648 /* Handles responses to an ajax request:
7649  * - finds the right dataType (mediates between content-type and expected dataType)
7650  * - returns the corresponding response
7651  */
7652 function ajaxHandleResponses( s, jqXHR, responses ) {
7653
7654         var ct, type, finalDataType, firstDataType,
7655                 contents = s.contents,
7656                 dataTypes = s.dataTypes;
7657
7658         // Remove auto dataType and get content-type in the process
7659         while ( dataTypes[ 0 ] === "*" ) {
7660                 dataTypes.shift();
7661                 if ( ct === undefined ) {
7662                         ct = s.mimeType || jqXHR.getResponseHeader("Content-Type");
7663                 }
7664         }
7665
7666         // Check if we're dealing with a known content-type
7667         if ( ct ) {
7668                 for ( type in contents ) {
7669                         if ( contents[ type ] && contents[ type ].test( ct ) ) {
7670                                 dataTypes.unshift( type );
7671                                 break;
7672                         }
7673                 }
7674         }
7675
7676         // Check to see if we have a response for the expected dataType
7677         if ( dataTypes[ 0 ] in responses ) {
7678                 finalDataType = dataTypes[ 0 ];
7679         } else {
7680                 // Try convertible dataTypes
7681                 for ( type in responses ) {
7682                         if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[0] ] ) {
7683                                 finalDataType = type;
7684                                 break;
7685                         }
7686                         if ( !firstDataType ) {
7687                                 firstDataType = type;
7688                         }
7689                 }
7690                 // Or just use first one
7691                 finalDataType = finalDataType || firstDataType;
7692         }
7693
7694         // If we found a dataType
7695         // We add the dataType to the list if needed
7696         // and return the corresponding response
7697         if ( finalDataType ) {
7698                 if ( finalDataType !== dataTypes[ 0 ] ) {
7699                         dataTypes.unshift( finalDataType );
7700                 }
7701                 return responses[ finalDataType ];
7702         }
7703 }
7704
7705 /* Chain conversions given the request and the original response
7706  * Also sets the responseXXX fields on the jqXHR instance
7707  */
7708 function ajaxConvert( s, response, jqXHR, isSuccess ) {
7709         var conv2, current, conv, tmp, prev,
7710                 converters = {},
7711                 // Work with a copy of dataTypes in case we need to modify it for conversion
7712                 dataTypes = s.dataTypes.slice();
7713
7714         // Create converters map with lowercased keys
7715         if ( dataTypes[ 1 ] ) {
7716                 for ( conv in s.converters ) {
7717                         converters[ conv.toLowerCase() ] = s.converters[ conv ];
7718                 }
7719         }
7720
7721         current = dataTypes.shift();
7722
7723         // Convert to each sequential dataType
7724         while ( current ) {
7725
7726                 if ( s.responseFields[ current ] ) {
7727                         jqXHR[ s.responseFields[ current ] ] = response;
7728                 }
7729
7730                 // Apply the dataFilter if provided
7731                 if ( !prev && isSuccess && s.dataFilter ) {
7732                         response = s.dataFilter( response, s.dataType );
7733                 }
7734
7735                 prev = current;
7736                 current = dataTypes.shift();
7737
7738                 if ( current ) {
7739
7740                 // There's only work to do if current dataType is non-auto
7741                         if ( current === "*" ) {
7742
7743                                 current = prev;
7744
7745                         // Convert response if prev dataType is non-auto and differs from current
7746                         } else if ( prev !== "*" && prev !== current ) {
7747
7748                                 // Seek a direct converter
7749                                 conv = converters[ prev + " " + current ] || converters[ "* " + current ];
7750
7751                                 // If none found, seek a pair
7752                                 if ( !conv ) {
7753                                         for ( conv2 in converters ) {
7754
7755                                                 // If conv2 outputs current
7756                                                 tmp = conv2.split( " " );
7757                                                 if ( tmp[ 1 ] === current ) {
7758
7759                                                         // If prev can be converted to accepted input
7760                                                         conv = converters[ prev + " " + tmp[ 0 ] ] ||
7761                                                                 converters[ "* " + tmp[ 0 ] ];
7762                                                         if ( conv ) {
7763                                                                 // Condense equivalence converters
7764                                                                 if ( conv === true ) {
7765                                                                         conv = converters[ conv2 ];
7766
7767                                                                 // Otherwise, insert the intermediate dataType
7768                                                                 } else if ( converters[ conv2 ] !== true ) {
7769                                                                         current = tmp[ 0 ];
7770                                                                         dataTypes.unshift( tmp[ 1 ] );
7771                                                                 }
7772                                                                 break;
7773                                                         }
7774                                                 }
7775                                         }
7776                                 }
7777
7778                                 // Apply converter (if not an equivalence)
7779                                 if ( conv !== true ) {
7780
7781                                         // Unless errors are allowed to bubble, catch and return them
7782                                         if ( conv && s[ "throws" ] ) {
7783                                                 response = conv( response );
7784                                         } else {
7785                                                 try {
7786                                                         response = conv( response );
7787                                                 } catch ( e ) {
7788                                                         return { state: "parsererror", error: conv ? e : "No conversion from " + prev + " to " + current };
7789                                                 }
7790                                         }
7791                                 }
7792                         }
7793                 }
7794         }
7795
7796         return { state: "success", data: response };
7797 }
7798
7799 jQuery.extend({
7800
7801         // Counter for holding the number of active queries
7802         active: 0,
7803
7804         // Last-Modified header cache for next request
7805         lastModified: {},
7806         etag: {},
7807
7808         ajaxSettings: {
7809                 url: ajaxLocation,
7810                 type: "GET",
7811                 isLocal: rlocalProtocol.test( ajaxLocParts[ 1 ] ),
7812                 global: true,
7813                 processData: true,
7814                 async: true,
7815                 contentType: "application/x-www-form-urlencoded; charset=UTF-8",
7816                 /*
7817                 timeout: 0,
7818                 data: null,
7819                 dataType: null,
7820                 username: null,
7821                 password: null,
7822                 cache: null,
7823                 throws: false,
7824                 traditional: false,
7825                 headers: {},
7826                 */
7827
7828                 accepts: {
7829                         "*": allTypes,
7830                         text: "text/plain",
7831                         html: "text/html",
7832                         xml: "application/xml, text/xml",
7833                         json: "application/json, text/javascript"
7834                 },
7835
7836                 contents: {
7837                         xml: /xml/,
7838                         html: /html/,
7839                         json: /json/
7840                 },
7841
7842                 responseFields: {
7843                         xml: "responseXML",
7844                         text: "responseText",
7845                         json: "responseJSON"
7846                 },
7847
7848                 // Data converters
7849                 // Keys separate source (or catchall "*") and destination types with a single space
7850                 converters: {
7851
7852                         // Convert anything to text
7853                         "* text": String,
7854
7855                         // Text to html (true = no transformation)
7856                         "text html": true,
7857
7858                         // Evaluate text as a json expression
7859                         "text json": jQuery.parseJSON,
7860
7861                         // Parse text as xml
7862                         "text xml": jQuery.parseXML
7863                 },
7864
7865                 // For options that shouldn't be deep extended:
7866                 // you can add your own custom options here if
7867                 // and when you create one that shouldn't be
7868                 // deep extended (see ajaxExtend)
7869                 flatOptions: {
7870                         url: true,
7871                         context: true
7872                 }
7873         },
7874
7875         // Creates a full fledged settings object into target
7876         // with both ajaxSettings and settings fields.
7877         // If target is omitted, writes into ajaxSettings.
7878         ajaxSetup: function( target, settings ) {
7879                 return settings ?
7880
7881                         // Building a settings object
7882                         ajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) :
7883
7884                         // Extending ajaxSettings
7885                         ajaxExtend( jQuery.ajaxSettings, target );
7886         },
7887
7888         ajaxPrefilter: addToPrefiltersOrTransports( prefilters ),
7889         ajaxTransport: addToPrefiltersOrTransports( transports ),
7890
7891         // Main method
7892         ajax: function( url, options ) {
7893
7894                 // If url is an object, simulate pre-1.5 signature
7895                 if ( typeof url === "object" ) {
7896                         options = url;
7897                         url = undefined;
7898                 }
7899
7900                 // Force options to be an object
7901                 options = options || {};
7902
7903                 var transport,
7904                         // URL without anti-cache param
7905                         cacheURL,
7906                         // Response headers
7907                         responseHeadersString,
7908                         responseHeaders,
7909                         // timeout handle
7910                         timeoutTimer,
7911                         // Cross-domain detection vars
7912                         parts,
7913                         // To know if global events are to be dispatched
7914                         fireGlobals,
7915                         // Loop variable
7916                         i,
7917                         // Create the final options object
7918                         s = jQuery.ajaxSetup( {}, options ),
7919                         // Callbacks context
7920                         callbackContext = s.context || s,
7921                         // Context for global events is callbackContext if it is a DOM node or jQuery collection
7922                         globalEventContext = s.context && ( callbackContext.nodeType || callbackContext.jquery ) ?
7923                                 jQuery( callbackContext ) :
7924                                 jQuery.event,
7925                         // Deferreds
7926                         deferred = jQuery.Deferred(),
7927                         completeDeferred = jQuery.Callbacks("once memory"),
7928                         // Status-dependent callbacks
7929                         statusCode = s.statusCode || {},
7930                         // Headers (they are sent all at once)
7931                         requestHeaders = {},
7932                         requestHeadersNames = {},
7933                         // The jqXHR state
7934                         state = 0,
7935                         // Default abort message
7936                         strAbort = "canceled",
7937                         // Fake xhr
7938                         jqXHR = {
7939                                 readyState: 0,
7940
7941                                 // Builds headers hashtable if needed
7942                                 getResponseHeader: function( key ) {
7943                                         var match;
7944                                         if ( state === 2 ) {
7945                                                 if ( !responseHeaders ) {
7946                                                         responseHeaders = {};
7947                                                         while ( (match = rheaders.exec( responseHeadersString )) ) {
7948                                                                 responseHeaders[ match[1].toLowerCase() ] = match[ 2 ];
7949                                                         }
7950                                                 }
7951                                                 match = responseHeaders[ key.toLowerCase() ];
7952                                         }
7953                                         return match == null ? null : match;
7954                                 },
7955
7956                                 // Raw string
7957                                 getAllResponseHeaders: function() {
7958                                         return state === 2 ? responseHeadersString : null;
7959                                 },
7960
7961                                 // Caches the header
7962                                 setRequestHeader: function( name, value ) {
7963                                         var lname = name.toLowerCase();
7964                                         if ( !state ) {
7965                                                 name = requestHeadersNames[ lname ] = requestHeadersNames[ lname ] || name;
7966                                                 requestHeaders[ name ] = value;
7967                                         }
7968                                         return this;
7969                                 },
7970
7971                                 // Overrides response content-type header
7972                                 overrideMimeType: function( type ) {
7973                                         if ( !state ) {
7974                                                 s.mimeType = type;
7975                                         }
7976                                         return this;
7977                                 },
7978
7979                                 // Status-dependent callbacks
7980                                 statusCode: function( map ) {
7981                                         var code;
7982                                         if ( map ) {
7983                                                 if ( state < 2 ) {
7984                                                         for ( code in map ) {
7985                                                                 // Lazy-add the new callback in a way that preserves old ones
7986                                                                 statusCode[ code ] = [ statusCode[ code ], map[ code ] ];
7987                                                         }
7988                                                 } else {
7989                                                         // Execute the appropriate callbacks
7990                                                         jqXHR.always( map[ jqXHR.status ] );
7991                                                 }
7992                                         }
7993                                         return this;
7994                                 },
7995
7996                                 // Cancel the request
7997                                 abort: function( statusText ) {
7998                                         var finalText = statusText || strAbort;
7999                                         if ( transport ) {
8000                                                 transport.abort( finalText );
8001                                         }
8002                                         done( 0, finalText );
8003                                         return this;
8004                                 }
8005                         };
8006
8007                 // Attach deferreds
8008                 deferred.promise( jqXHR ).complete = completeDeferred.add;
8009                 jqXHR.success = jqXHR.done;
8010                 jqXHR.error = jqXHR.fail;
8011
8012                 // Remove hash character (#7531: and string promotion)
8013                 // Add protocol if not provided (prefilters might expect it)
8014                 // Handle falsy url in the settings object (#10093: consistency with old signature)
8015                 // We also use the url parameter if available
8016                 s.url = ( ( url || s.url || ajaxLocation ) + "" ).replace( rhash, "" )
8017                         .replace( rprotocol, ajaxLocParts[ 1 ] + "//" );
8018
8019                 // Alias method option to type as per ticket #12004
8020                 s.type = options.method || options.type || s.method || s.type;
8021
8022                 // Extract dataTypes list
8023                 s.dataTypes = jQuery.trim( s.dataType || "*" ).toLowerCase().match( rnotwhite ) || [ "" ];
8024
8025                 // A cross-domain request is in order when we have a protocol:host:port mismatch
8026                 if ( s.crossDomain == null ) {
8027                         parts = rurl.exec( s.url.toLowerCase() );
8028                         s.crossDomain = !!( parts &&
8029                                 ( parts[ 1 ] !== ajaxLocParts[ 1 ] || parts[ 2 ] !== ajaxLocParts[ 2 ] ||
8030                                         ( parts[ 3 ] || ( parts[ 1 ] === "http:" ? "80" : "443" ) ) !==
8031                                                 ( ajaxLocParts[ 3 ] || ( ajaxLocParts[ 1 ] === "http:" ? "80" : "443" ) ) )
8032                         );
8033                 }
8034
8035                 // Convert data if not already a string
8036                 if ( s.data && s.processData && typeof s.data !== "string" ) {
8037                         s.data = jQuery.param( s.data, s.traditional );
8038                 }
8039
8040                 // Apply prefilters
8041                 inspectPrefiltersOrTransports( prefilters, s, options, jqXHR );
8042
8043                 // If request was aborted inside a prefilter, stop there
8044                 if ( state === 2 ) {
8045                         return jqXHR;
8046                 }
8047
8048                 // We can fire global events as of now if asked to
8049                 fireGlobals = s.global;
8050
8051                 // Watch for a new set of requests
8052                 if ( fireGlobals && jQuery.active++ === 0 ) {
8053                         jQuery.event.trigger("ajaxStart");
8054                 }
8055
8056                 // Uppercase the type
8057                 s.type = s.type.toUpperCase();
8058
8059                 // Determine if request has content
8060                 s.hasContent = !rnoContent.test( s.type );
8061
8062                 // Save the URL in case we're toying with the If-Modified-Since
8063                 // and/or If-None-Match header later on
8064                 cacheURL = s.url;
8065
8066                 // More options handling for requests with no content
8067                 if ( !s.hasContent ) {
8068
8069                         // If data is available, append data to url
8070                         if ( s.data ) {
8071                                 cacheURL = ( s.url += ( rquery.test( cacheURL ) ? "&" : "?" ) + s.data );
8072                                 // #9682: remove data so that it's not used in an eventual retry
8073                                 delete s.data;
8074                         }
8075
8076                         // Add anti-cache in url if needed
8077                         if ( s.cache === false ) {
8078                                 s.url = rts.test( cacheURL ) ?
8079
8080                                         // If there is already a '_' parameter, set its value
8081                                         cacheURL.replace( rts, "$1_=" + nonce++ ) :
8082
8083                                         // Otherwise add one to the end
8084                                         cacheURL + ( rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + nonce++;
8085                         }
8086                 }
8087
8088                 // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
8089                 if ( s.ifModified ) {
8090                         if ( jQuery.lastModified[ cacheURL ] ) {
8091                                 jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ cacheURL ] );
8092                         }
8093                         if ( jQuery.etag[ cacheURL ] ) {
8094                                 jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ cacheURL ] );
8095                         }
8096                 }
8097
8098                 // Set the correct header, if data is being sent
8099                 if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) {
8100                         jqXHR.setRequestHeader( "Content-Type", s.contentType );
8101                 }
8102
8103                 // Set the Accepts header for the server, depending on the dataType
8104                 jqXHR.setRequestHeader(
8105                         "Accept",
8106                         s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[0] ] ?
8107                                 s.accepts[ s.dataTypes[0] ] + ( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) :
8108                                 s.accepts[ "*" ]
8109                 );
8110
8111                 // Check for headers option
8112                 for ( i in s.headers ) {
8113                         jqXHR.setRequestHeader( i, s.headers[ i ] );
8114                 }
8115
8116                 // Allow custom headers/mimetypes and early abort
8117                 if ( s.beforeSend && ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || state === 2 ) ) {
8118                         // Abort if not done already and return
8119                         return jqXHR.abort();
8120                 }
8121
8122                 // aborting is no longer a cancellation
8123                 strAbort = "abort";
8124
8125                 // Install callbacks on deferreds
8126                 for ( i in { success: 1, error: 1, complete: 1 } ) {
8127                         jqXHR[ i ]( s[ i ] );
8128                 }
8129
8130                 // Get transport
8131                 transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR );
8132
8133                 // If no transport, we auto-abort
8134                 if ( !transport ) {
8135                         done( -1, "No Transport" );
8136                 } else {
8137                         jqXHR.readyState = 1;
8138
8139                         // Send global event
8140                         if ( fireGlobals ) {
8141                                 globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] );
8142                         }
8143                         // Timeout
8144                         if ( s.async && s.timeout > 0 ) {
8145                                 timeoutTimer = setTimeout(function() {
8146                                         jqXHR.abort("timeout");
8147                                 }, s.timeout );
8148                         }
8149
8150                         try {
8151                                 state = 1;
8152                                 transport.send( requestHeaders, done );
8153                         } catch ( e ) {
8154                                 // Propagate exception as error if not done
8155                                 if ( state < 2 ) {
8156                                         done( -1, e );
8157                                 // Simply rethrow otherwise
8158                                 } else {
8159                                         throw e;
8160                                 }
8161                         }
8162                 }
8163
8164                 // Callback for when everything is done
8165                 function done( status, nativeStatusText, responses, headers ) {
8166                         var isSuccess, success, error, response, modified,
8167                                 statusText = nativeStatusText;
8168
8169                         // Called once
8170                         if ( state === 2 ) {
8171                                 return;
8172                         }
8173
8174                         // State is "done" now
8175                         state = 2;
8176
8177                         // Clear timeout if it exists
8178                         if ( timeoutTimer ) {
8179                                 clearTimeout( timeoutTimer );
8180                         }
8181
8182                         // Dereference transport for early garbage collection
8183                         // (no matter how long the jqXHR object will be used)
8184                         transport = undefined;
8185
8186                         // Cache response headers
8187                         responseHeadersString = headers || "";
8188
8189                         // Set readyState
8190                         jqXHR.readyState = status > 0 ? 4 : 0;
8191
8192                         // Determine if successful
8193                         isSuccess = status >= 200 && status < 300 || status === 304;
8194
8195                         // Get response data
8196                         if ( responses ) {
8197                                 response = ajaxHandleResponses( s, jqXHR, responses );
8198                         }
8199
8200                         // Convert no matter what (that way responseXXX fields are always set)
8201                         response = ajaxConvert( s, response, jqXHR, isSuccess );
8202
8203                         // If successful, handle type chaining
8204                         if ( isSuccess ) {
8205
8206                                 // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
8207                                 if ( s.ifModified ) {
8208                                         modified = jqXHR.getResponseHeader("Last-Modified");
8209                                         if ( modified ) {
8210                                                 jQuery.lastModified[ cacheURL ] = modified;
8211                                         }
8212                                         modified = jqXHR.getResponseHeader("etag");
8213                                         if ( modified ) {
8214                                                 jQuery.etag[ cacheURL ] = modified;
8215                                         }
8216                                 }
8217
8218                                 // if no content
8219                                 if ( status === 204 || s.type === "HEAD" ) {
8220                                         statusText = "nocontent";
8221
8222                                 // if not modified
8223                                 } else if ( status === 304 ) {
8224                                         statusText = "notmodified";
8225
8226                                 // If we have data, let's convert it
8227                                 } else {
8228                                         statusText = response.state;
8229                                         success = response.data;
8230                                         error = response.error;
8231                                         isSuccess = !error;
8232                                 }
8233                         } else {
8234                                 // We extract error from statusText
8235                                 // then normalize statusText and status for non-aborts
8236                                 error = statusText;
8237                                 if ( status || !statusText ) {
8238                                         statusText = "error";
8239                                         if ( status < 0 ) {
8240                                                 status = 0;
8241                                         }
8242                                 }
8243                         }
8244
8245                         // Set data for the fake xhr object
8246                         jqXHR.status = status;
8247                         jqXHR.statusText = ( nativeStatusText || statusText ) + "";
8248
8249                         // Success/Error
8250                         if ( isSuccess ) {
8251                                 deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] );
8252                         } else {
8253                                 deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] );
8254                         }
8255
8256                         // Status-dependent callbacks
8257                         jqXHR.statusCode( statusCode );
8258                         statusCode = undefined;
8259
8260                         if ( fireGlobals ) {
8261                                 globalEventContext.trigger( isSuccess ? "ajaxSuccess" : "ajaxError",
8262                                         [ jqXHR, s, isSuccess ? success : error ] );
8263                         }
8264
8265                         // Complete
8266                         completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] );
8267
8268                         if ( fireGlobals ) {
8269                                 globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] );
8270                                 // Handle the global AJAX counter
8271                                 if ( !( --jQuery.active ) ) {
8272                                         jQuery.event.trigger("ajaxStop");
8273                                 }
8274                         }
8275                 }
8276
8277                 return jqXHR;
8278         },
8279
8280         getJSON: function( url, data, callback ) {
8281                 return jQuery.get( url, data, callback, "json" );
8282         },
8283
8284         getScript: function( url, callback ) {
8285                 return jQuery.get( url, undefined, callback, "script" );
8286         }
8287 });
8288
8289 jQuery.each( [ "get", "post" ], function( i, method ) {
8290         jQuery[ method ] = function( url, data, callback, type ) {
8291                 // shift arguments if data argument was omitted
8292                 if ( jQuery.isFunction( data ) ) {
8293                         type = type || callback;
8294                         callback = data;
8295                         data = undefined;
8296                 }
8297
8298                 return jQuery.ajax({
8299                         url: url,
8300                         type: method,
8301                         dataType: type,
8302                         data: data,
8303                         success: callback
8304                 });
8305         };
8306 });
8307
8308 // Attach a bunch of functions for handling common AJAX events
8309 jQuery.each( [ "ajaxStart", "ajaxStop", "ajaxComplete", "ajaxError", "ajaxSuccess", "ajaxSend" ], function( i, type ) {
8310         jQuery.fn[ type ] = function( fn ) {
8311                 return this.on( type, fn );
8312         };
8313 });
8314
8315
8316 jQuery._evalUrl = function( url ) {
8317         return jQuery.ajax({
8318                 url: url,
8319                 type: "GET",
8320                 dataType: "script",
8321                 async: false,
8322                 global: false,
8323                 "throws": true
8324         });
8325 };
8326
8327
8328 jQuery.fn.extend({
8329         wrapAll: function( html ) {
8330                 var wrap;
8331
8332                 if ( jQuery.isFunction( html ) ) {
8333                         return this.each(function( i ) {
8334                                 jQuery( this ).wrapAll( html.call(this, i) );
8335                         });
8336                 }
8337
8338                 if ( this[ 0 ] ) {
8339
8340                         // The elements to wrap the target around
8341                         wrap = jQuery( html, this[ 0 ].ownerDocument ).eq( 0 ).clone( true );
8342
8343                         if ( this[ 0 ].parentNode ) {
8344                                 wrap.insertBefore( this[ 0 ] );
8345                         }
8346
8347                         wrap.map(function() {
8348                                 var elem = this;
8349
8350                                 while ( elem.firstElementChild ) {
8351                                         elem = elem.firstElementChild;
8352                                 }
8353
8354                                 return elem;
8355                         }).append( this );
8356                 }
8357
8358                 return this;
8359         },
8360
8361         wrapInner: function( html ) {
8362                 if ( jQuery.isFunction( html ) ) {
8363                         return this.each(function( i ) {
8364                                 jQuery( this ).wrapInner( html.call(this, i) );
8365                         });
8366                 }
8367
8368                 return this.each(function() {
8369                         var self = jQuery( this ),
8370                                 contents = self.contents();
8371
8372                         if ( contents.length ) {
8373                                 contents.wrapAll( html );
8374
8375                         } else {
8376                                 self.append( html );
8377                         }
8378                 });
8379         },
8380
8381         wrap: function( html ) {
8382                 var isFunction = jQuery.isFunction( html );
8383
8384                 return this.each(function( i ) {
8385                         jQuery( this ).wrapAll( isFunction ? html.call(this, i) : html );
8386                 });
8387         },
8388
8389         unwrap: function() {
8390                 return this.parent().each(function() {
8391                         if ( !jQuery.nodeName( this, "body" ) ) {
8392                                 jQuery( this ).replaceWith( this.childNodes );
8393                         }
8394                 }).end();
8395         }
8396 });
8397
8398
8399 jQuery.expr.filters.hidden = function( elem ) {
8400         // Support: Opera <= 12.12
8401         // Opera reports offsetWidths and offsetHeights less than zero on some elements
8402         return elem.offsetWidth <= 0 && elem.offsetHeight <= 0;
8403 };
8404 jQuery.expr.filters.visible = function( elem ) {
8405         return !jQuery.expr.filters.hidden( elem );
8406 };
8407
8408
8409
8410
8411 var r20 = /%20/g,
8412         rbracket = /\[\]$/,
8413         rCRLF = /\r?\n/g,
8414         rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i,
8415         rsubmittable = /^(?:input|select|textarea|keygen)/i;
8416
8417 function buildParams( prefix, obj, traditional, add ) {
8418         var name;
8419
8420         if ( jQuery.isArray( obj ) ) {
8421                 // Serialize array item.
8422                 jQuery.each( obj, function( i, v ) {
8423                         if ( traditional || rbracket.test( prefix ) ) {
8424                                 // Treat each array item as a scalar.
8425                                 add( prefix, v );
8426
8427                         } else {
8428                                 // Item is non-scalar (array or object), encode its numeric index.
8429                                 buildParams( prefix + "[" + ( typeof v === "object" ? i : "" ) + "]", v, traditional, add );
8430                         }
8431                 });
8432
8433         } else if ( !traditional && jQuery.type( obj ) === "object" ) {
8434                 // Serialize object item.
8435                 for ( name in obj ) {
8436                         buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add );
8437                 }
8438
8439         } else {
8440                 // Serialize scalar item.
8441                 add( prefix, obj );
8442         }
8443 }
8444
8445 // Serialize an array of form elements or a set of
8446 // key/values into a query string
8447 jQuery.param = function( a, traditional ) {
8448         var prefix,
8449                 s = [],
8450                 add = function( key, value ) {
8451                         // If value is a function, invoke it and return its value
8452                         value = jQuery.isFunction( value ) ? value() : ( value == null ? "" : value );
8453                         s[ s.length ] = encodeURIComponent( key ) + "=" + encodeURIComponent( value );
8454                 };
8455
8456         // Set traditional to true for jQuery <= 1.3.2 behavior.
8457         if ( traditional === undefined ) {
8458                 traditional = jQuery.ajaxSettings && jQuery.ajaxSettings.traditional;
8459         }
8460
8461         // If an array was passed in, assume that it is an array of form elements.
8462         if ( jQuery.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) {
8463                 // Serialize the form elements
8464                 jQuery.each( a, function() {
8465                         add( this.name, this.value );
8466                 });
8467
8468         } else {
8469                 // If traditional, encode the "old" way (the way 1.3.2 or older
8470                 // did it), otherwise encode params recursively.
8471                 for ( prefix in a ) {
8472                         buildParams( prefix, a[ prefix ], traditional, add );
8473                 }
8474         }
8475
8476         // Return the resulting serialization
8477         return s.join( "&" ).replace( r20, "+" );
8478 };
8479
8480 jQuery.fn.extend({
8481         serialize: function() {
8482                 return jQuery.param( this.serializeArray() );
8483         },
8484         serializeArray: function() {
8485                 return this.map(function() {
8486                         // Can add propHook for "elements" to filter or add form elements
8487                         var elements = jQuery.prop( this, "elements" );
8488                         return elements ? jQuery.makeArray( elements ) : this;
8489                 })
8490                 .filter(function() {
8491                         var type = this.type;
8492
8493                         // Use .is( ":disabled" ) so that fieldset[disabled] works
8494                         return this.name && !jQuery( this ).is( ":disabled" ) &&
8495                                 rsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) &&
8496                                 ( this.checked || !rcheckableType.test( type ) );
8497                 })
8498                 .map(function( i, elem ) {
8499                         var val = jQuery( this ).val();
8500
8501                         return val == null ?
8502                                 null :
8503                                 jQuery.isArray( val ) ?
8504                                         jQuery.map( val, function( val ) {
8505                                                 return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
8506                                         }) :
8507                                         { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
8508                 }).get();
8509         }
8510 });
8511
8512
8513 jQuery.ajaxSettings.xhr = function() {
8514         try {
8515                 return new XMLHttpRequest();
8516         } catch( e ) {}
8517 };
8518
8519 var xhrId = 0,
8520         xhrCallbacks = {},
8521         xhrSuccessStatus = {
8522                 // file protocol always yields status code 0, assume 200
8523                 0: 200,
8524                 // Support: IE9
8525                 // #1450: sometimes IE returns 1223 when it should be 204
8526                 1223: 204
8527         },
8528         xhrSupported = jQuery.ajaxSettings.xhr();
8529
8530 // Support: IE9
8531 // Open requests must be manually aborted on unload (#5280)
8532 if ( window.ActiveXObject ) {
8533         jQuery( window ).on( "unload", function() {
8534                 for ( var key in xhrCallbacks ) {
8535                         xhrCallbacks[ key ]();
8536                 }
8537         });
8538 }
8539
8540 support.cors = !!xhrSupported && ( "withCredentials" in xhrSupported );
8541 support.ajax = xhrSupported = !!xhrSupported;
8542
8543 jQuery.ajaxTransport(function( options ) {
8544         var callback;
8545
8546         // Cross domain only allowed if supported through XMLHttpRequest
8547         if ( support.cors || xhrSupported && !options.crossDomain ) {
8548                 return {
8549                         send: function( headers, complete ) {
8550                                 var i,
8551                                         xhr = options.xhr(),
8552                                         id = ++xhrId;
8553
8554                                 xhr.open( options.type, options.url, options.async, options.username, options.password );
8555
8556                                 // Apply custom fields if provided
8557                                 if ( options.xhrFields ) {
8558                                         for ( i in options.xhrFields ) {
8559                                                 xhr[ i ] = options.xhrFields[ i ];
8560                                         }
8561                                 }
8562
8563                                 // Override mime type if needed
8564                                 if ( options.mimeType && xhr.overrideMimeType ) {
8565                                         xhr.overrideMimeType( options.mimeType );
8566                                 }
8567
8568                                 // X-Requested-With header
8569                                 // For cross-domain requests, seeing as conditions for a preflight are
8570                                 // akin to a jigsaw puzzle, we simply never set it to be sure.
8571                                 // (it can always be set on a per-request basis or even using ajaxSetup)
8572                                 // For same-domain requests, won't change header if already provided.
8573                                 if ( !options.crossDomain && !headers["X-Requested-With"] ) {
8574                                         headers["X-Requested-With"] = "XMLHttpRequest";
8575                                 }
8576
8577                                 // Set headers
8578                                 for ( i in headers ) {
8579                                         xhr.setRequestHeader( i, headers[ i ] );
8580                                 }
8581
8582                                 // Callback
8583                                 callback = function( type ) {
8584                                         return function() {
8585                                                 if ( callback ) {
8586                                                         delete xhrCallbacks[ id ];
8587                                                         callback = xhr.onload = xhr.onerror = null;
8588
8589                                                         if ( type === "abort" ) {
8590                                                                 xhr.abort();
8591                                                         } else if ( type === "error" ) {
8592                                                                 complete(
8593                                                                         // file: protocol always yields status 0; see #8605, #14207
8594                                                                         xhr.status,
8595                                                                         xhr.statusText
8596                                                                 );
8597                                                         } else {
8598                                                                 complete(
8599                                                                         xhrSuccessStatus[ xhr.status ] || xhr.status,
8600                                                                         xhr.statusText,
8601                                                                         // Support: IE9
8602                                                                         // Accessing binary-data responseText throws an exception
8603                                                                         // (#11426)
8604                                                                         typeof xhr.responseText === "string" ? {
8605                                                                                 text: xhr.responseText
8606                                                                         } : undefined,
8607                                                                         xhr.getAllResponseHeaders()
8608                                                                 );
8609                                                         }
8610                                                 }
8611                                         };
8612                                 };
8613
8614                                 // Listen to events
8615                                 xhr.onload = callback();
8616                                 xhr.onerror = callback("error");
8617
8618                                 // Create the abort callback
8619                                 callback = xhrCallbacks[ id ] = callback("abort");
8620
8621                                 try {
8622                                         // Do send the request (this may raise an exception)
8623                                         xhr.send( options.hasContent && options.data || null );
8624                                 } catch ( e ) {
8625                                         // #14683: Only rethrow if this hasn't been notified as an error yet
8626                                         if ( callback ) {
8627                                                 throw e;
8628                                         }
8629                                 }
8630                         },
8631
8632                         abort: function() {
8633                                 if ( callback ) {
8634                                         callback();
8635                                 }
8636                         }
8637                 };
8638         }
8639 });
8640
8641
8642
8643
8644 // Install script dataType
8645 jQuery.ajaxSetup({
8646         accepts: {
8647                 script: "text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"
8648         },
8649         contents: {
8650                 script: /(?:java|ecma)script/
8651         },
8652         converters: {
8653                 "text script": function( text ) {
8654                         jQuery.globalEval( text );
8655                         return text;
8656                 }
8657         }
8658 });
8659
8660 // Handle cache's special case and crossDomain
8661 jQuery.ajaxPrefilter( "script", function( s ) {
8662         if ( s.cache === undefined ) {
8663                 s.cache = false;
8664         }
8665         if ( s.crossDomain ) {
8666                 s.type = "GET";
8667         }
8668 });
8669
8670 // Bind script tag hack transport
8671 jQuery.ajaxTransport( "script", function( s ) {
8672         // This transport only deals with cross domain requests
8673         if ( s.crossDomain ) {
8674                 var script, callback;
8675                 return {
8676                         send: function( _, complete ) {
8677                                 script = jQuery("<script>").prop({
8678                                         async: true,
8679                                         charset: s.scriptCharset,
8680                                         src: s.url
8681                                 }).on(
8682                                         "load error",
8683                                         callback = function( evt ) {
8684                                                 script.remove();
8685                                                 callback = null;
8686                                                 if ( evt ) {
8687                                                         complete( evt.type === "error" ? 404 : 200, evt.type );
8688                                                 }
8689                                         }
8690                                 );
8691                                 document.head.appendChild( script[ 0 ] );
8692                         },
8693                         abort: function() {
8694                                 if ( callback ) {
8695                                         callback();
8696                                 }
8697                         }
8698                 };
8699         }
8700 });
8701
8702
8703
8704
8705 var oldCallbacks = [],
8706         rjsonp = /(=)\?(?=&|$)|\?\?/;
8707
8708 // Default jsonp settings
8709 jQuery.ajaxSetup({
8710         jsonp: "callback",
8711         jsonpCallback: function() {
8712                 var callback = oldCallbacks.pop() || ( jQuery.expando + "_" + ( nonce++ ) );
8713                 this[ callback ] = true;
8714                 return callback;
8715         }
8716 });
8717
8718 // Detect, normalize options and install callbacks for jsonp requests
8719 jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) {
8720
8721         var callbackName, overwritten, responseContainer,
8722                 jsonProp = s.jsonp !== false && ( rjsonp.test( s.url ) ?
8723                         "url" :
8724                         typeof s.data === "string" && !( s.contentType || "" ).indexOf("application/x-www-form-urlencoded") && rjsonp.test( s.data ) && "data"
8725                 );
8726
8727         // Handle iff the expected data type is "jsonp" or we have a parameter to set
8728         if ( jsonProp || s.dataTypes[ 0 ] === "jsonp" ) {
8729
8730                 // Get callback name, remembering preexisting value associated with it
8731                 callbackName = s.jsonpCallback = jQuery.isFunction( s.jsonpCallback ) ?
8732                         s.jsonpCallback() :
8733                         s.jsonpCallback;
8734
8735                 // Insert callback into url or form data
8736                 if ( jsonProp ) {
8737                         s[ jsonProp ] = s[ jsonProp ].replace( rjsonp, "$1" + callbackName );
8738                 } else if ( s.jsonp !== false ) {
8739                         s.url += ( rquery.test( s.url ) ? "&" : "?" ) + s.jsonp + "=" + callbackName;
8740                 }
8741
8742                 // Use data converter to retrieve json after script execution
8743                 s.converters["script json"] = function() {
8744                         if ( !responseContainer ) {
8745                                 jQuery.error( callbackName + " was not called" );
8746                         }
8747                         return responseContainer[ 0 ];
8748                 };
8749
8750                 // force json dataType
8751                 s.dataTypes[ 0 ] = "json";
8752
8753                 // Install callback
8754                 overwritten = window[ callbackName ];
8755                 window[ callbackName ] = function() {
8756                         responseContainer = arguments;
8757                 };
8758
8759                 // Clean-up function (fires after converters)
8760                 jqXHR.always(function() {
8761                         // Restore preexisting value
8762                         window[ callbackName ] = overwritten;
8763
8764                         // Save back as free
8765                         if ( s[ callbackName ] ) {
8766                                 // make sure that re-using the options doesn't screw things around
8767                                 s.jsonpCallback = originalSettings.jsonpCallback;
8768
8769                                 // save the callback name for future use
8770                                 oldCallbacks.push( callbackName );
8771                         }
8772
8773                         // Call if it was a function and we have a response
8774                         if ( responseContainer && jQuery.isFunction( overwritten ) ) {
8775                                 overwritten( responseContainer[ 0 ] );
8776                         }
8777
8778                         responseContainer = overwritten = undefined;
8779                 });
8780
8781                 // Delegate to script
8782                 return "script";
8783         }
8784 });
8785
8786
8787
8788
8789 // data: string of html
8790 // context (optional): If specified, the fragment will be created in this context, defaults to document
8791 // keepScripts (optional): If true, will include scripts passed in the html string
8792 jQuery.parseHTML = function( data, context, keepScripts ) {
8793         if ( !data || typeof data !== "string" ) {
8794                 return null;
8795         }
8796         if ( typeof context === "boolean" ) {
8797                 keepScripts = context;
8798                 context = false;
8799         }
8800         context = context || document;
8801
8802         var parsed = rsingleTag.exec( data ),
8803                 scripts = !keepScripts && [];
8804
8805         // Single tag
8806         if ( parsed ) {
8807                 return [ context.createElement( parsed[1] ) ];
8808         }
8809
8810         parsed = jQuery.buildFragment( [ data ], context, scripts );
8811
8812         if ( scripts && scripts.length ) {
8813                 jQuery( scripts ).remove();
8814         }
8815
8816         return jQuery.merge( [], parsed.childNodes );
8817 };
8818
8819
8820 // Keep a copy of the old load method
8821 var _load = jQuery.fn.load;
8822
8823 /**
8824  * Load a url into a page
8825  */
8826 jQuery.fn.load = function( url, params, callback ) {
8827         if ( typeof url !== "string" && _load ) {
8828                 return _load.apply( this, arguments );
8829         }
8830
8831         var selector, type, response,
8832                 self = this,
8833                 off = url.indexOf(" ");
8834
8835         if ( off >= 0 ) {
8836                 selector = jQuery.trim( url.slice( off ) );
8837                 url = url.slice( 0, off );
8838         }
8839
8840         // If it's a function
8841         if ( jQuery.isFunction( params ) ) {
8842
8843                 // We assume that it's the callback
8844                 callback = params;
8845                 params = undefined;
8846
8847         // Otherwise, build a param string
8848         } else if ( params && typeof params === "object" ) {
8849                 type = "POST";
8850         }
8851
8852         // If we have elements to modify, make the request
8853         if ( self.length > 0 ) {
8854                 jQuery.ajax({
8855                         url: url,
8856
8857                         // if "type" variable is undefined, then "GET" method will be used
8858                         type: type,
8859                         dataType: "html",
8860                         data: params
8861                 }).done(function( responseText ) {
8862
8863                         // Save response for use in complete callback
8864                         response = arguments;
8865
8866                         self.html( selector ?
8867
8868                                 // If a selector was specified, locate the right elements in a dummy div
8869                                 // Exclude scripts to avoid IE 'Permission Denied' errors
8870                                 jQuery("<div>").append( jQuery.parseHTML( responseText ) ).find( selector ) :
8871
8872                                 // Otherwise use the full result
8873                                 responseText );
8874
8875                 }).complete( callback && function( jqXHR, status ) {
8876                         self.each( callback, response || [ jqXHR.responseText, status, jqXHR ] );
8877                 });
8878         }
8879
8880         return this;
8881 };
8882
8883
8884
8885
8886 jQuery.expr.filters.animated = function( elem ) {
8887         return jQuery.grep(jQuery.timers, function( fn ) {
8888                 return elem === fn.elem;
8889         }).length;
8890 };
8891
8892
8893
8894
8895 var docElem = window.document.documentElement;
8896
8897 /**
8898  * Gets a window from an element
8899  */
8900 function getWindow( elem ) {
8901         return jQuery.isWindow( elem ) ? elem : elem.nodeType === 9 && elem.defaultView;
8902 }
8903
8904 jQuery.offset = {
8905         setOffset: function( elem, options, i ) {
8906                 var curPosition, curLeft, curCSSTop, curTop, curOffset, curCSSLeft, calculatePosition,
8907                         position = jQuery.css( elem, "position" ),
8908                         curElem = jQuery( elem ),
8909                         props = {};
8910
8911                 // Set position first, in-case top/left are set even on static elem
8912                 if ( position === "static" ) {
8913                         elem.style.position = "relative";
8914                 }
8915
8916                 curOffset = curElem.offset();
8917                 curCSSTop = jQuery.css( elem, "top" );
8918                 curCSSLeft = jQuery.css( elem, "left" );
8919                 calculatePosition = ( position === "absolute" || position === "fixed" ) &&
8920                         ( curCSSTop + curCSSLeft ).indexOf("auto") > -1;
8921
8922                 // Need to be able to calculate position if either top or left is auto and position is either absolute or fixed
8923                 if ( calculatePosition ) {
8924                         curPosition = curElem.position();
8925                         curTop = curPosition.top;
8926                         curLeft = curPosition.left;
8927
8928                 } else {
8929                         curTop = parseFloat( curCSSTop ) || 0;
8930                         curLeft = parseFloat( curCSSLeft ) || 0;
8931                 }
8932
8933                 if ( jQuery.isFunction( options ) ) {
8934                         options = options.call( elem, i, curOffset );
8935                 }
8936
8937                 if ( options.top != null ) {
8938                         props.top = ( options.top - curOffset.top ) + curTop;
8939                 }
8940                 if ( options.left != null ) {
8941                         props.left = ( options.left - curOffset.left ) + curLeft;
8942                 }
8943
8944                 if ( "using" in options ) {
8945                         options.using.call( elem, props );
8946
8947                 } else {
8948                         curElem.css( props );
8949                 }
8950         }
8951 };
8952
8953 jQuery.fn.extend({
8954         offset: function( options ) {
8955                 if ( arguments.length ) {
8956                         return options === undefined ?
8957                                 this :
8958                                 this.each(function( i ) {
8959                                         jQuery.offset.setOffset( this, options, i );
8960                                 });
8961                 }
8962
8963                 var docElem, win,
8964                         elem = this[ 0 ],
8965                         box = { top: 0, left: 0 },
8966                         doc = elem && elem.ownerDocument;
8967
8968                 if ( !doc ) {
8969                         return;
8970                 }
8971
8972                 docElem = doc.documentElement;
8973
8974                 // Make sure it's not a disconnected DOM node
8975                 if ( !jQuery.contains( docElem, elem ) ) {
8976                         return box;
8977                 }
8978
8979                 // If we don't have gBCR, just use 0,0 rather than error
8980                 // BlackBerry 5, iOS 3 (original iPhone)
8981                 if ( typeof elem.getBoundingClientRect !== strundefined ) {
8982                         box = elem.getBoundingClientRect();
8983                 }
8984                 win = getWindow( doc );
8985                 return {
8986                         top: box.top + win.pageYOffset - docElem.clientTop,
8987                         left: box.left + win.pageXOffset - docElem.clientLeft
8988                 };
8989         },
8990
8991         position: function() {
8992                 if ( !this[ 0 ] ) {
8993                         return;
8994                 }
8995
8996                 var offsetParent, offset,
8997                         elem = this[ 0 ],
8998                         parentOffset = { top: 0, left: 0 };
8999
9000                 // Fixed elements are offset from window (parentOffset = {top:0, left: 0}, because it is its only offset parent
9001                 if ( jQuery.css( elem, "position" ) === "fixed" ) {
9002                         // We assume that getBoundingClientRect is available when computed position is fixed
9003                         offset = elem.getBoundingClientRect();
9004
9005                 } else {
9006                         // Get *real* offsetParent
9007                         offsetParent = this.offsetParent();
9008
9009                         // Get correct offsets
9010                         offset = this.offset();
9011                         if ( !jQuery.nodeName( offsetParent[ 0 ], "html" ) ) {
9012                                 parentOffset = offsetParent.offset();
9013                         }
9014
9015                         // Add offsetParent borders
9016                         parentOffset.top += jQuery.css( offsetParent[ 0 ], "borderTopWidth", true );
9017                         parentOffset.left += jQuery.css( offsetParent[ 0 ], "borderLeftWidth", true );
9018                 }
9019
9020                 // Subtract parent offsets and element margins
9021                 return {
9022                         top: offset.top - parentOffset.top - jQuery.css( elem, "marginTop", true ),
9023                         left: offset.left - parentOffset.left - jQuery.css( elem, "marginLeft", true )
9024                 };
9025         },
9026
9027         offsetParent: function() {
9028                 return this.map(function() {
9029                         var offsetParent = this.offsetParent || docElem;
9030
9031                         while ( offsetParent && ( !jQuery.nodeName( offsetParent, "html" ) && jQuery.css( offsetParent, "position" ) === "static" ) ) {
9032                                 offsetParent = offsetParent.offsetParent;
9033                         }
9034
9035                         return offsetParent || docElem;
9036                 });
9037         }
9038 });
9039
9040 // Create scrollLeft and scrollTop methods
9041 jQuery.each( { scrollLeft: "pageXOffset", scrollTop: "pageYOffset" }, function( method, prop ) {
9042         var top = "pageYOffset" === prop;
9043
9044         jQuery.fn[ method ] = function( val ) {
9045                 return access( this, function( elem, method, val ) {
9046                         var win = getWindow( elem );
9047
9048                         if ( val === undefined ) {
9049                                 return win ? win[ prop ] : elem[ method ];
9050                         }
9051
9052                         if ( win ) {
9053                                 win.scrollTo(
9054                                         !top ? val : window.pageXOffset,
9055                                         top ? val : window.pageYOffset
9056                                 );
9057
9058                         } else {
9059                                 elem[ method ] = val;
9060                         }
9061                 }, method, val, arguments.length, null );
9062         };
9063 });
9064
9065 // Add the top/left cssHooks using jQuery.fn.position
9066 // Webkit bug: https://bugs.webkit.org/show_bug.cgi?id=29084
9067 // getComputedStyle returns percent when specified for top/left/bottom/right
9068 // rather than make the css module depend on the offset module, we just check for it here
9069 jQuery.each( [ "top", "left" ], function( i, prop ) {
9070         jQuery.cssHooks[ prop ] = addGetHookIf( support.pixelPosition,
9071                 function( elem, computed ) {
9072                         if ( computed ) {
9073                                 computed = curCSS( elem, prop );
9074                                 // if curCSS returns percentage, fallback to offset
9075                                 return rnumnonpx.test( computed ) ?
9076                                         jQuery( elem ).position()[ prop ] + "px" :
9077                                         computed;
9078                         }
9079                 }
9080         );
9081 });
9082
9083
9084 // Create innerHeight, innerWidth, height, width, outerHeight and outerWidth methods
9085 jQuery.each( { Height: "height", Width: "width" }, function( name, type ) {
9086         jQuery.each( { padding: "inner" + name, content: type, "": "outer" + name }, function( defaultExtra, funcName ) {
9087                 // margin is only for outerHeight, outerWidth
9088                 jQuery.fn[ funcName ] = function( margin, value ) {
9089                         var chainable = arguments.length && ( defaultExtra || typeof margin !== "boolean" ),
9090                                 extra = defaultExtra || ( margin === true || value === true ? "margin" : "border" );
9091
9092                         return access( this, function( elem, type, value ) {
9093                                 var doc;
9094
9095                                 if ( jQuery.isWindow( elem ) ) {
9096                                         // As of 5/8/2012 this will yield incorrect results for Mobile Safari, but there
9097                                         // isn't a whole lot we can do. See pull request at this URL for discussion:
9098                                         // https://github.com/jquery/jquery/pull/764
9099                                         return elem.document.documentElement[ "client" + name ];
9100                                 }
9101
9102                                 // Get document width or height
9103                                 if ( elem.nodeType === 9 ) {
9104                                         doc = elem.documentElement;
9105
9106                                         // Either scroll[Width/Height] or offset[Width/Height] or client[Width/Height],
9107                                         // whichever is greatest
9108                                         return Math.max(
9109                                                 elem.body[ "scroll" + name ], doc[ "scroll" + name ],
9110                                                 elem.body[ "offset" + name ], doc[ "offset" + name ],
9111                                                 doc[ "client" + name ]
9112                                         );
9113                                 }
9114
9115                                 return value === undefined ?
9116                                         // Get width or height on the element, requesting but not forcing parseFloat
9117                                         jQuery.css( elem, type, extra ) :
9118
9119                                         // Set width or height on the element
9120                                         jQuery.style( elem, type, value, extra );
9121                         }, type, chainable ? margin : undefined, chainable, null );
9122                 };
9123         });
9124 });
9125
9126
9127 // The number of elements contained in the matched element set
9128 jQuery.fn.size = function() {
9129         return this.length;
9130 };
9131
9132 jQuery.fn.andSelf = jQuery.fn.addBack;
9133
9134
9135
9136
9137 // Register as a named AMD module, since jQuery can be concatenated with other
9138 // files that may use define, but not via a proper concatenation script that
9139 // understands anonymous AMD modules. A named AMD is safest and most robust
9140 // way to register. Lowercase jquery is used because AMD module names are
9141 // derived from file names, and jQuery is normally delivered in a lowercase
9142 // file name. Do this after creating the global so that if an AMD module wants
9143 // to call noConflict to hide this version of jQuery, it will work.
9144
9145 // Note that for maximum portability, libraries that are not jQuery should
9146 // declare themselves as anonymous modules, and avoid setting a global if an
9147 // AMD loader is present. jQuery is a special case. For more information, see
9148 // https://github.com/jrburke/requirejs/wiki/Updating-existing-libraries#wiki-anon
9149
9150 if ( typeof define === "function" && define.amd ) {
9151         define( "jquery", [], function() {
9152                 return jQuery;
9153         });
9154 }
9155
9156
9157
9158
9159 var
9160         // Map over jQuery in case of overwrite
9161         _jQuery = window.jQuery,
9162
9163         // Map over the $ in case of overwrite
9164         _$ = window.$;
9165
9166 jQuery.noConflict = function( deep ) {
9167         if ( window.$ === jQuery ) {
9168                 window.$ = _$;
9169         }
9170
9171         if ( deep && window.jQuery === jQuery ) {
9172                 window.jQuery = _jQuery;
9173         }
9174
9175         return jQuery;
9176 };
9177
9178 // Expose jQuery and $ identifiers, even in
9179 // AMD (#7102#comment:10, https://github.com/jquery/jquery/pull/557)
9180 // and CommonJS for browser emulators (#13566)
9181 if ( typeof noGlobal === strundefined ) {
9182         window.jQuery = window.$ = jQuery;
9183 }
9184
9185
9186
9187
9188 return jQuery;
9189
9190 }));
9191
9192 /**
9193  * @license AngularJS v1.4.8
9194  * (c) 2010-2015 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.4.8/' +
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 /**
9384  * @ngdoc function
9385  * @name angular.lowercase
9386  * @module ng
9387  * @kind function
9388  *
9389  * @description Converts the specified string to lowercase.
9390  * @param {string} string String to be converted to lowercase.
9391  * @returns {string} Lowercased string.
9392  */
9393 var lowercase = function(string) {return isString(string) ? string.toLowerCase() : string;};
9394 var hasOwnProperty = Object.prototype.hasOwnProperty;
9395
9396 /**
9397  * @ngdoc function
9398  * @name angular.uppercase
9399  * @module ng
9400  * @kind function
9401  *
9402  * @description Converts the specified string to uppercase.
9403  * @param {string} string String to be converted to uppercase.
9404  * @returns {string} Uppercased string.
9405  */
9406 var uppercase = function(string) {return isString(string) ? string.toUpperCase() : string;};
9407
9408
9409 var manualLowercase = function(s) {
9410   /* jshint bitwise: false */
9411   return isString(s)
9412       ? s.replace(/[A-Z]/g, function(ch) {return String.fromCharCode(ch.charCodeAt(0) | 32);})
9413       : s;
9414 };
9415 var manualUppercase = function(s) {
9416   /* jshint bitwise: false */
9417   return isString(s)
9418       ? s.replace(/[a-z]/g, function(ch) {return String.fromCharCode(ch.charCodeAt(0) & ~32);})
9419       : s;
9420 };
9421
9422
9423 // String#toLowerCase and String#toUpperCase don't produce correct results in browsers with Turkish
9424 // locale, for this reason we need to detect this case and redefine lowercase/uppercase methods
9425 // with correct but slower alternatives.
9426 if ('i' !== 'I'.toLowerCase()) {
9427   lowercase = manualLowercase;
9428   uppercase = manualUppercase;
9429 }
9430
9431
9432 var
9433     msie,             // holds major version number for IE, or NaN if UA is not IE.
9434     jqLite,           // delay binding since jQuery could be loaded after us.
9435     jQuery,           // delay binding
9436     slice             = [].slice,
9437     splice            = [].splice,
9438     push              = [].push,
9439     toString          = Object.prototype.toString,
9440     getPrototypeOf    = Object.getPrototypeOf,
9441     ngMinErr          = minErr('ng'),
9442
9443     /** @name angular */
9444     angular           = window.angular || (window.angular = {}),
9445     angularModule,
9446     uid               = 0;
9447
9448 /**
9449  * documentMode is an IE-only property
9450  * http://msdn.microsoft.com/en-us/library/ie/cc196988(v=vs.85).aspx
9451  */
9452 msie = document.documentMode;
9453
9454
9455 /**
9456  * @private
9457  * @param {*} obj
9458  * @return {boolean} Returns true if `obj` is an array or array-like object (NodeList, Arguments,
9459  *                   String ...)
9460  */
9461 function isArrayLike(obj) {
9462
9463   // `null`, `undefined` and `window` are not array-like
9464   if (obj == null || isWindow(obj)) return false;
9465
9466   // arrays, strings and jQuery/jqLite objects are array like
9467   // * jqLite is either the jQuery or jqLite constructor function
9468   // * we have to check the existance of jqLite first as this method is called
9469   //   via the forEach method when constructing the jqLite object in the first place
9470   if (isArray(obj) || isString(obj) || (jqLite && obj instanceof jqLite)) return true;
9471
9472   // Support: iOS 8.2 (not reproducible in simulator)
9473   // "length" in obj used to prevent JIT error (gh-11508)
9474   var length = "length" in Object(obj) && obj.length;
9475
9476   // NodeList objects (with `item` method) and
9477   // other objects with suitable length characteristics are array-like
9478   return isNumber(length) &&
9479     (length >= 0 && (length - 1) in obj || typeof obj.item == 'function');
9480 }
9481
9482 /**
9483  * @ngdoc function
9484  * @name angular.forEach
9485  * @module ng
9486  * @kind function
9487  *
9488  * @description
9489  * Invokes the `iterator` function once for each item in `obj` collection, which can be either an
9490  * object or an array. The `iterator` function is invoked with `iterator(value, key, obj)`, where `value`
9491  * is the value of an object property or an array element, `key` is the object property key or
9492  * array element index and obj is the `obj` itself. Specifying a `context` for the function is optional.
9493  *
9494  * It is worth noting that `.forEach` does not iterate over inherited properties because it filters
9495  * using the `hasOwnProperty` method.
9496  *
9497  * Unlike ES262's
9498  * [Array.prototype.forEach](http://www.ecma-international.org/ecma-262/5.1/#sec-15.4.4.18),
9499  * Providing 'undefined' or 'null' values for `obj` will not throw a TypeError, but rather just
9500  * return the value provided.
9501  *
9502    ```js
9503      var values = {name: 'misko', gender: 'male'};
9504      var log = [];
9505      angular.forEach(values, function(value, key) {
9506        this.push(key + ': ' + value);
9507      }, log);
9508      expect(log).toEqual(['name: misko', 'gender: male']);
9509    ```
9510  *
9511  * @param {Object|Array} obj Object to iterate over.
9512  * @param {Function} iterator Iterator function.
9513  * @param {Object=} context Object to become context (`this`) for the iterator function.
9514  * @returns {Object|Array} Reference to `obj`.
9515  */
9516
9517 function forEach(obj, iterator, context) {
9518   var key, length;
9519   if (obj) {
9520     if (isFunction(obj)) {
9521       for (key in obj) {
9522         // Need to check if hasOwnProperty exists,
9523         // as on IE8 the result of querySelectorAll is an object without a hasOwnProperty function
9524         if (key != 'prototype' && key != 'length' && key != 'name' && (!obj.hasOwnProperty || obj.hasOwnProperty(key))) {
9525           iterator.call(context, obj[key], key, obj);
9526         }
9527       }
9528     } else if (isArray(obj) || isArrayLike(obj)) {
9529       var isPrimitive = typeof obj !== 'object';
9530       for (key = 0, length = obj.length; key < length; key++) {
9531         if (isPrimitive || key in obj) {
9532           iterator.call(context, obj[key], key, obj);
9533         }
9534       }
9535     } else if (obj.forEach && obj.forEach !== forEach) {
9536         obj.forEach(iterator, context, obj);
9537     } else if (isBlankObject(obj)) {
9538       // createMap() fast path --- Safe to avoid hasOwnProperty check because prototype chain is empty
9539       for (key in obj) {
9540         iterator.call(context, obj[key], key, obj);
9541       }
9542     } else if (typeof obj.hasOwnProperty === 'function') {
9543       // Slow path for objects inheriting Object.prototype, hasOwnProperty check needed
9544       for (key in obj) {
9545         if (obj.hasOwnProperty(key)) {
9546           iterator.call(context, obj[key], key, obj);
9547         }
9548       }
9549     } else {
9550       // Slow path for objects which do not have a method `hasOwnProperty`
9551       for (key in obj) {
9552         if (hasOwnProperty.call(obj, key)) {
9553           iterator.call(context, obj[key], key, obj);
9554         }
9555       }
9556     }
9557   }
9558   return obj;
9559 }
9560
9561 function forEachSorted(obj, iterator, context) {
9562   var keys = Object.keys(obj).sort();
9563   for (var i = 0; i < keys.length; i++) {
9564     iterator.call(context, obj[keys[i]], keys[i]);
9565   }
9566   return keys;
9567 }
9568
9569
9570 /**
9571  * when using forEach the params are value, key, but it is often useful to have key, value.
9572  * @param {function(string, *)} iteratorFn
9573  * @returns {function(*, string)}
9574  */
9575 function reverseParams(iteratorFn) {
9576   return function(value, key) { iteratorFn(key, value); };
9577 }
9578
9579 /**
9580  * A consistent way of creating unique IDs in angular.
9581  *
9582  * Using simple numbers allows us to generate 28.6 million unique ids per second for 10 years before
9583  * we hit number precision issues in JavaScript.
9584  *
9585  * Math.pow(2,53) / 60 / 60 / 24 / 365 / 10 = 28.6M
9586  *
9587  * @returns {number} an unique alpha-numeric string
9588  */
9589 function nextUid() {
9590   return ++uid;
9591 }
9592
9593
9594 /**
9595  * Set or clear the hashkey for an object.
9596  * @param obj object
9597  * @param h the hashkey (!truthy to delete the hashkey)
9598  */
9599 function setHashKey(obj, h) {
9600   if (h) {
9601     obj.$$hashKey = h;
9602   } else {
9603     delete obj.$$hashKey;
9604   }
9605 }
9606
9607
9608 function baseExtend(dst, objs, deep) {
9609   var h = dst.$$hashKey;
9610
9611   for (var i = 0, ii = objs.length; i < ii; ++i) {
9612     var obj = objs[i];
9613     if (!isObject(obj) && !isFunction(obj)) continue;
9614     var keys = Object.keys(obj);
9615     for (var j = 0, jj = keys.length; j < jj; j++) {
9616       var key = keys[j];
9617       var src = obj[key];
9618
9619       if (deep && isObject(src)) {
9620         if (isDate(src)) {
9621           dst[key] = new Date(src.valueOf());
9622         } else if (isRegExp(src)) {
9623           dst[key] = new RegExp(src);
9624         } else if (src.nodeName) {
9625           dst[key] = src.cloneNode(true);
9626         } else if (isElement(src)) {
9627           dst[key] = src.clone();
9628         } else {
9629           if (!isObject(dst[key])) dst[key] = isArray(src) ? [] : {};
9630           baseExtend(dst[key], [src], true);
9631         }
9632       } else {
9633         dst[key] = src;
9634       }
9635     }
9636   }
9637
9638   setHashKey(dst, h);
9639   return dst;
9640 }
9641
9642 /**
9643  * @ngdoc function
9644  * @name angular.extend
9645  * @module ng
9646  * @kind function
9647  *
9648  * @description
9649  * Extends the destination object `dst` by copying own enumerable properties from the `src` object(s)
9650  * to `dst`. You can specify multiple `src` objects. If you want to preserve original objects, you can do so
9651  * by passing an empty object as the target: `var object = angular.extend({}, object1, object2)`.
9652  *
9653  * **Note:** Keep in mind that `angular.extend` does not support recursive merge (deep copy). Use
9654  * {@link angular.merge} for this.
9655  *
9656  * @param {Object} dst Destination object.
9657  * @param {...Object} src Source object(s).
9658  * @returns {Object} Reference to `dst`.
9659  */
9660 function extend(dst) {
9661   return baseExtend(dst, slice.call(arguments, 1), false);
9662 }
9663
9664
9665 /**
9666 * @ngdoc function
9667 * @name angular.merge
9668 * @module ng
9669 * @kind function
9670 *
9671 * @description
9672 * Deeply extends the destination object `dst` by copying own enumerable properties from the `src` object(s)
9673 * to `dst`. You can specify multiple `src` objects. If you want to preserve original objects, you can do so
9674 * by passing an empty object as the target: `var object = angular.merge({}, object1, object2)`.
9675 *
9676 * Unlike {@link angular.extend extend()}, `merge()` recursively descends into object properties of source
9677 * objects, performing a deep copy.
9678 *
9679 * @param {Object} dst Destination object.
9680 * @param {...Object} src Source object(s).
9681 * @returns {Object} Reference to `dst`.
9682 */
9683 function merge(dst) {
9684   return baseExtend(dst, slice.call(arguments, 1), true);
9685 }
9686
9687
9688
9689 function toInt(str) {
9690   return parseInt(str, 10);
9691 }
9692
9693
9694 function inherit(parent, extra) {
9695   return extend(Object.create(parent), extra);
9696 }
9697
9698 /**
9699  * @ngdoc function
9700  * @name angular.noop
9701  * @module ng
9702  * @kind function
9703  *
9704  * @description
9705  * A function that performs no operations. This function can be useful when writing code in the
9706  * functional style.
9707    ```js
9708      function foo(callback) {
9709        var result = calculateResult();
9710        (callback || angular.noop)(result);
9711      }
9712    ```
9713  */
9714 function noop() {}
9715 noop.$inject = [];
9716
9717
9718 /**
9719  * @ngdoc function
9720  * @name angular.identity
9721  * @module ng
9722  * @kind function
9723  *
9724  * @description
9725  * A function that returns its first argument. This function is useful when writing code in the
9726  * functional style.
9727  *
9728    ```js
9729      function transformer(transformationFn, value) {
9730        return (transformationFn || angular.identity)(value);
9731      };
9732    ```
9733   * @param {*} value to be returned.
9734   * @returns {*} the value passed in.
9735  */
9736 function identity($) {return $;}
9737 identity.$inject = [];
9738
9739
9740 function valueFn(value) {return function() {return value;};}
9741
9742 function hasCustomToString(obj) {
9743   return isFunction(obj.toString) && obj.toString !== toString;
9744 }
9745
9746
9747 /**
9748  * @ngdoc function
9749  * @name angular.isUndefined
9750  * @module ng
9751  * @kind function
9752  *
9753  * @description
9754  * Determines if a reference is undefined.
9755  *
9756  * @param {*} value Reference to check.
9757  * @returns {boolean} True if `value` is undefined.
9758  */
9759 function isUndefined(value) {return typeof value === 'undefined';}
9760
9761
9762 /**
9763  * @ngdoc function
9764  * @name angular.isDefined
9765  * @module ng
9766  * @kind function
9767  *
9768  * @description
9769  * Determines if a reference is defined.
9770  *
9771  * @param {*} value Reference to check.
9772  * @returns {boolean} True if `value` is defined.
9773  */
9774 function isDefined(value) {return typeof value !== 'undefined';}
9775
9776
9777 /**
9778  * @ngdoc function
9779  * @name angular.isObject
9780  * @module ng
9781  * @kind function
9782  *
9783  * @description
9784  * Determines if a reference is an `Object`. Unlike `typeof` in JavaScript, `null`s are not
9785  * considered to be objects. Note that JavaScript arrays are objects.
9786  *
9787  * @param {*} value Reference to check.
9788  * @returns {boolean} True if `value` is an `Object` but not `null`.
9789  */
9790 function isObject(value) {
9791   // http://jsperf.com/isobject4
9792   return value !== null && typeof value === 'object';
9793 }
9794
9795
9796 /**
9797  * Determine if a value is an object with a null prototype
9798  *
9799  * @returns {boolean} True if `value` is an `Object` with a null prototype
9800  */
9801 function isBlankObject(value) {
9802   return value !== null && typeof value === 'object' && !getPrototypeOf(value);
9803 }
9804
9805
9806 /**
9807  * @ngdoc function
9808  * @name angular.isString
9809  * @module ng
9810  * @kind function
9811  *
9812  * @description
9813  * Determines if a reference is a `String`.
9814  *
9815  * @param {*} value Reference to check.
9816  * @returns {boolean} True if `value` is a `String`.
9817  */
9818 function isString(value) {return typeof value === 'string';}
9819
9820
9821 /**
9822  * @ngdoc function
9823  * @name angular.isNumber
9824  * @module ng
9825  * @kind function
9826  *
9827  * @description
9828  * Determines if a reference is a `Number`.
9829  *
9830  * This includes the "special" numbers `NaN`, `+Infinity` and `-Infinity`.
9831  *
9832  * If you wish to exclude these then you can use the native
9833  * [`isFinite'](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/isFinite)
9834  * method.
9835  *
9836  * @param {*} value Reference to check.
9837  * @returns {boolean} True if `value` is a `Number`.
9838  */
9839 function isNumber(value) {return typeof value === 'number';}
9840
9841
9842 /**
9843  * @ngdoc function
9844  * @name angular.isDate
9845  * @module ng
9846  * @kind function
9847  *
9848  * @description
9849  * Determines if a value is a date.
9850  *
9851  * @param {*} value Reference to check.
9852  * @returns {boolean} True if `value` is a `Date`.
9853  */
9854 function isDate(value) {
9855   return toString.call(value) === '[object Date]';
9856 }
9857
9858
9859 /**
9860  * @ngdoc function
9861  * @name angular.isArray
9862  * @module ng
9863  * @kind function
9864  *
9865  * @description
9866  * Determines if a reference is an `Array`.
9867  *
9868  * @param {*} value Reference to check.
9869  * @returns {boolean} True if `value` is an `Array`.
9870  */
9871 var isArray = Array.isArray;
9872
9873 /**
9874  * @ngdoc function
9875  * @name angular.isFunction
9876  * @module ng
9877  * @kind function
9878  *
9879  * @description
9880  * Determines if a reference is a `Function`.
9881  *
9882  * @param {*} value Reference to check.
9883  * @returns {boolean} True if `value` is a `Function`.
9884  */
9885 function isFunction(value) {return typeof value === 'function';}
9886
9887
9888 /**
9889  * Determines if a value is a regular expression object.
9890  *
9891  * @private
9892  * @param {*} value Reference to check.
9893  * @returns {boolean} True if `value` is a `RegExp`.
9894  */
9895 function isRegExp(value) {
9896   return toString.call(value) === '[object RegExp]';
9897 }
9898
9899
9900 /**
9901  * Checks if `obj` is a window object.
9902  *
9903  * @private
9904  * @param {*} obj Object to check
9905  * @returns {boolean} True if `obj` is a window obj.
9906  */
9907 function isWindow(obj) {
9908   return obj && obj.window === obj;
9909 }
9910
9911
9912 function isScope(obj) {
9913   return obj && obj.$evalAsync && obj.$watch;
9914 }
9915
9916
9917 function isFile(obj) {
9918   return toString.call(obj) === '[object File]';
9919 }
9920
9921
9922 function isFormData(obj) {
9923   return toString.call(obj) === '[object FormData]';
9924 }
9925
9926
9927 function isBlob(obj) {
9928   return toString.call(obj) === '[object Blob]';
9929 }
9930
9931
9932 function isBoolean(value) {
9933   return typeof value === 'boolean';
9934 }
9935
9936
9937 function isPromiseLike(obj) {
9938   return obj && isFunction(obj.then);
9939 }
9940
9941
9942 var TYPED_ARRAY_REGEXP = /^\[object (?:Uint8|Uint8Clamped|Uint16|Uint32|Int8|Int16|Int32|Float32|Float64)Array\]$/;
9943 function isTypedArray(value) {
9944   return value && isNumber(value.length) && TYPED_ARRAY_REGEXP.test(toString.call(value));
9945 }
9946
9947
9948 var trim = function(value) {
9949   return isString(value) ? value.trim() : value;
9950 };
9951
9952 // Copied from:
9953 // http://docs.closure-library.googlecode.com/git/local_closure_goog_string_string.js.source.html#line1021
9954 // Prereq: s is a string.
9955 var escapeForRegexp = function(s) {
9956   return s.replace(/([-()\[\]{}+?*.$\^|,:#<!\\])/g, '\\$1').
9957            replace(/\x08/g, '\\x08');
9958 };
9959
9960
9961 /**
9962  * @ngdoc function
9963  * @name angular.isElement
9964  * @module ng
9965  * @kind function
9966  *
9967  * @description
9968  * Determines if a reference is a DOM element (or wrapped jQuery element).
9969  *
9970  * @param {*} value Reference to check.
9971  * @returns {boolean} True if `value` is a DOM element (or wrapped jQuery element).
9972  */
9973 function isElement(node) {
9974   return !!(node &&
9975     (node.nodeName  // we are a direct element
9976     || (node.prop && node.attr && node.find)));  // we have an on and find method part of jQuery API
9977 }
9978
9979 /**
9980  * @param str 'key1,key2,...'
9981  * @returns {object} in the form of {key1:true, key2:true, ...}
9982  */
9983 function makeMap(str) {
9984   var obj = {}, items = str.split(","), i;
9985   for (i = 0; i < items.length; i++) {
9986     obj[items[i]] = true;
9987   }
9988   return obj;
9989 }
9990
9991
9992 function nodeName_(element) {
9993   return lowercase(element.nodeName || (element[0] && element[0].nodeName));
9994 }
9995
9996 function includes(array, obj) {
9997   return Array.prototype.indexOf.call(array, obj) != -1;
9998 }
9999
10000 function arrayRemove(array, value) {
10001   var index = array.indexOf(value);
10002   if (index >= 0) {
10003     array.splice(index, 1);
10004   }
10005   return index;
10006 }
10007
10008 /**
10009  * @ngdoc function
10010  * @name angular.copy
10011  * @module ng
10012  * @kind function
10013  *
10014  * @description
10015  * Creates a deep copy of `source`, which should be an object or an array.
10016  *
10017  * * If no destination is supplied, a copy of the object or array is created.
10018  * * If a destination is provided, all of its elements (for arrays) or properties (for objects)
10019  *   are deleted and then all elements/properties from the source are copied to it.
10020  * * If `source` is not an object or array (inc. `null` and `undefined`), `source` is returned.
10021  * * If `source` is identical to 'destination' an exception will be thrown.
10022  *
10023  * @param {*} source The source that will be used to make a copy.
10024  *                   Can be any type, including primitives, `null`, and `undefined`.
10025  * @param {(Object|Array)=} destination Destination into which the source is copied. If
10026  *     provided, must be of the same type as `source`.
10027  * @returns {*} The copy or updated `destination`, if `destination` was specified.
10028  *
10029  * @example
10030  <example module="copyExample">
10031  <file name="index.html">
10032  <div ng-controller="ExampleController">
10033  <form novalidate class="simple-form">
10034  Name: <input type="text" ng-model="user.name" /><br />
10035  E-mail: <input type="email" ng-model="user.email" /><br />
10036  Gender: <input type="radio" ng-model="user.gender" value="male" />male
10037  <input type="radio" ng-model="user.gender" value="female" />female<br />
10038  <button ng-click="reset()">RESET</button>
10039  <button ng-click="update(user)">SAVE</button>
10040  </form>
10041  <pre>form = {{user | json}}</pre>
10042  <pre>master = {{master | json}}</pre>
10043  </div>
10044
10045  <script>
10046   angular.module('copyExample', [])
10047     .controller('ExampleController', ['$scope', function($scope) {
10048       $scope.master= {};
10049
10050       $scope.update = function(user) {
10051         // Example with 1 argument
10052         $scope.master= angular.copy(user);
10053       };
10054
10055       $scope.reset = function() {
10056         // Example with 2 arguments
10057         angular.copy($scope.master, $scope.user);
10058       };
10059
10060       $scope.reset();
10061     }]);
10062  </script>
10063  </file>
10064  </example>
10065  */
10066 function copy(source, destination) {
10067   var stackSource = [];
10068   var stackDest = [];
10069
10070   if (destination) {
10071     if (isTypedArray(destination)) {
10072       throw ngMinErr('cpta', "Can't copy! TypedArray destination cannot be mutated.");
10073     }
10074     if (source === destination) {
10075       throw ngMinErr('cpi', "Can't copy! Source and destination are identical.");
10076     }
10077
10078     // Empty the destination object
10079     if (isArray(destination)) {
10080       destination.length = 0;
10081     } else {
10082       forEach(destination, function(value, key) {
10083         if (key !== '$$hashKey') {
10084           delete destination[key];
10085         }
10086       });
10087     }
10088
10089     stackSource.push(source);
10090     stackDest.push(destination);
10091     return copyRecurse(source, destination);
10092   }
10093
10094   return copyElement(source);
10095
10096   function copyRecurse(source, destination) {
10097     var h = destination.$$hashKey;
10098     var result, key;
10099     if (isArray(source)) {
10100       for (var i = 0, ii = source.length; i < ii; i++) {
10101         destination.push(copyElement(source[i]));
10102       }
10103     } else if (isBlankObject(source)) {
10104       // createMap() fast path --- Safe to avoid hasOwnProperty check because prototype chain is empty
10105       for (key in source) {
10106         destination[key] = copyElement(source[key]);
10107       }
10108     } else if (source && typeof source.hasOwnProperty === 'function') {
10109       // Slow path, which must rely on hasOwnProperty
10110       for (key in source) {
10111         if (source.hasOwnProperty(key)) {
10112           destination[key] = copyElement(source[key]);
10113         }
10114       }
10115     } else {
10116       // Slowest path --- hasOwnProperty can't be called as a method
10117       for (key in source) {
10118         if (hasOwnProperty.call(source, key)) {
10119           destination[key] = copyElement(source[key]);
10120         }
10121       }
10122     }
10123     setHashKey(destination, h);
10124     return destination;
10125   }
10126
10127   function copyElement(source) {
10128     // Simple values
10129     if (!isObject(source)) {
10130       return source;
10131     }
10132
10133     // Already copied values
10134     var index = stackSource.indexOf(source);
10135     if (index !== -1) {
10136       return stackDest[index];
10137     }
10138
10139     if (isWindow(source) || isScope(source)) {
10140       throw ngMinErr('cpws',
10141         "Can't copy! Making copies of Window or Scope instances is not supported.");
10142     }
10143
10144     var needsRecurse = false;
10145     var destination;
10146
10147     if (isArray(source)) {
10148       destination = [];
10149       needsRecurse = true;
10150     } else if (isTypedArray(source)) {
10151       destination = new source.constructor(source);
10152     } else if (isDate(source)) {
10153       destination = new Date(source.getTime());
10154     } else if (isRegExp(source)) {
10155       destination = new RegExp(source.source, source.toString().match(/[^\/]*$/)[0]);
10156       destination.lastIndex = source.lastIndex;
10157     } else if (isFunction(source.cloneNode)) {
10158         destination = source.cloneNode(true);
10159     } else {
10160       destination = Object.create(getPrototypeOf(source));
10161       needsRecurse = true;
10162     }
10163
10164     stackSource.push(source);
10165     stackDest.push(destination);
10166
10167     return needsRecurse
10168       ? copyRecurse(source, destination)
10169       : destination;
10170   }
10171 }
10172
10173 /**
10174  * Creates a shallow copy of an object, an array or a primitive.
10175  *
10176  * Assumes that there are no proto properties for objects.
10177  */
10178 function shallowCopy(src, dst) {
10179   if (isArray(src)) {
10180     dst = dst || [];
10181
10182     for (var i = 0, ii = src.length; i < ii; i++) {
10183       dst[i] = src[i];
10184     }
10185   } else if (isObject(src)) {
10186     dst = dst || {};
10187
10188     for (var key in src) {
10189       if (!(key.charAt(0) === '$' && key.charAt(1) === '$')) {
10190         dst[key] = src[key];
10191       }
10192     }
10193   }
10194
10195   return dst || src;
10196 }
10197
10198
10199 /**
10200  * @ngdoc function
10201  * @name angular.equals
10202  * @module ng
10203  * @kind function
10204  *
10205  * @description
10206  * Determines if two objects or two values are equivalent. Supports value types, regular
10207  * expressions, arrays and objects.
10208  *
10209  * Two objects or values are considered equivalent if at least one of the following is true:
10210  *
10211  * * Both objects or values pass `===` comparison.
10212  * * Both objects or values are of the same type and all of their properties are equal by
10213  *   comparing them with `angular.equals`.
10214  * * Both values are NaN. (In JavaScript, NaN == NaN => false. But we consider two NaN as equal)
10215  * * Both values represent the same regular expression (In JavaScript,
10216  *   /abc/ == /abc/ => false. But we consider two regular expressions as equal when their textual
10217  *   representation matches).
10218  *
10219  * During a property comparison, properties of `function` type and properties with names
10220  * that begin with `$` are ignored.
10221  *
10222  * Scope and DOMWindow objects are being compared only by identify (`===`).
10223  *
10224  * @param {*} o1 Object or value to compare.
10225  * @param {*} o2 Object or value to compare.
10226  * @returns {boolean} True if arguments are equal.
10227  */
10228 function equals(o1, o2) {
10229   if (o1 === o2) return true;
10230   if (o1 === null || o2 === null) return false;
10231   if (o1 !== o1 && o2 !== o2) return true; // NaN === NaN
10232   var t1 = typeof o1, t2 = typeof o2, length, key, keySet;
10233   if (t1 == t2) {
10234     if (t1 == 'object') {
10235       if (isArray(o1)) {
10236         if (!isArray(o2)) return false;
10237         if ((length = o1.length) == o2.length) {
10238           for (key = 0; key < length; key++) {
10239             if (!equals(o1[key], o2[key])) return false;
10240           }
10241           return true;
10242         }
10243       } else if (isDate(o1)) {
10244         if (!isDate(o2)) return false;
10245         return equals(o1.getTime(), o2.getTime());
10246       } else if (isRegExp(o1)) {
10247         return isRegExp(o2) ? o1.toString() == o2.toString() : false;
10248       } else {
10249         if (isScope(o1) || isScope(o2) || isWindow(o1) || isWindow(o2) ||
10250           isArray(o2) || isDate(o2) || isRegExp(o2)) return false;
10251         keySet = createMap();
10252         for (key in o1) {
10253           if (key.charAt(0) === '$' || isFunction(o1[key])) continue;
10254           if (!equals(o1[key], o2[key])) return false;
10255           keySet[key] = true;
10256         }
10257         for (key in o2) {
10258           if (!(key in keySet) &&
10259               key.charAt(0) !== '$' &&
10260               isDefined(o2[key]) &&
10261               !isFunction(o2[key])) return false;
10262         }
10263         return true;
10264       }
10265     }
10266   }
10267   return false;
10268 }
10269
10270 var csp = function() {
10271   if (!isDefined(csp.rules)) {
10272
10273
10274     var ngCspElement = (document.querySelector('[ng-csp]') ||
10275                     document.querySelector('[data-ng-csp]'));
10276
10277     if (ngCspElement) {
10278       var ngCspAttribute = ngCspElement.getAttribute('ng-csp') ||
10279                     ngCspElement.getAttribute('data-ng-csp');
10280       csp.rules = {
10281         noUnsafeEval: !ngCspAttribute || (ngCspAttribute.indexOf('no-unsafe-eval') !== -1),
10282         noInlineStyle: !ngCspAttribute || (ngCspAttribute.indexOf('no-inline-style') !== -1)
10283       };
10284     } else {
10285       csp.rules = {
10286         noUnsafeEval: noUnsafeEval(),
10287         noInlineStyle: false
10288       };
10289     }
10290   }
10291
10292   return csp.rules;
10293
10294   function noUnsafeEval() {
10295     try {
10296       /* jshint -W031, -W054 */
10297       new Function('');
10298       /* jshint +W031, +W054 */
10299       return false;
10300     } catch (e) {
10301       return true;
10302     }
10303   }
10304 };
10305
10306 /**
10307  * @ngdoc directive
10308  * @module ng
10309  * @name ngJq
10310  *
10311  * @element ANY
10312  * @param {string=} ngJq the name of the library available under `window`
10313  * to be used for angular.element
10314  * @description
10315  * Use this directive to force the angular.element library.  This should be
10316  * used to force either jqLite by leaving ng-jq blank or setting the name of
10317  * the jquery variable under window (eg. jQuery).
10318  *
10319  * Since angular looks for this directive when it is loaded (doesn't wait for the
10320  * DOMContentLoaded event), it must be placed on an element that comes before the script
10321  * which loads angular. Also, only the first instance of `ng-jq` will be used and all
10322  * others ignored.
10323  *
10324  * @example
10325  * This example shows how to force jqLite using the `ngJq` directive to the `html` tag.
10326  ```html
10327  <!doctype html>
10328  <html ng-app ng-jq>
10329  ...
10330  ...
10331  </html>
10332  ```
10333  * @example
10334  * This example shows how to use a jQuery based library of a different name.
10335  * The library name must be available at the top most 'window'.
10336  ```html
10337  <!doctype html>
10338  <html ng-app ng-jq="jQueryLib">
10339  ...
10340  ...
10341  </html>
10342  ```
10343  */
10344 var jq = function() {
10345   if (isDefined(jq.name_)) return jq.name_;
10346   var el;
10347   var i, ii = ngAttrPrefixes.length, prefix, name;
10348   for (i = 0; i < ii; ++i) {
10349     prefix = ngAttrPrefixes[i];
10350     if (el = document.querySelector('[' + prefix.replace(':', '\\:') + 'jq]')) {
10351       name = el.getAttribute(prefix + 'jq');
10352       break;
10353     }
10354   }
10355
10356   return (jq.name_ = name);
10357 };
10358
10359 function concat(array1, array2, index) {
10360   return array1.concat(slice.call(array2, index));
10361 }
10362
10363 function sliceArgs(args, startIndex) {
10364   return slice.call(args, startIndex || 0);
10365 }
10366
10367
10368 /* jshint -W101 */
10369 /**
10370  * @ngdoc function
10371  * @name angular.bind
10372  * @module ng
10373  * @kind function
10374  *
10375  * @description
10376  * Returns a function which calls function `fn` bound to `self` (`self` becomes the `this` for
10377  * `fn`). You can supply optional `args` that are prebound to the function. This feature is also
10378  * known as [partial application](http://en.wikipedia.org/wiki/Partial_application), as
10379  * distinguished from [function currying](http://en.wikipedia.org/wiki/Currying#Contrast_with_partial_function_application).
10380  *
10381  * @param {Object} self Context which `fn` should be evaluated in.
10382  * @param {function()} fn Function to be bound.
10383  * @param {...*} args Optional arguments to be prebound to the `fn` function call.
10384  * @returns {function()} Function that wraps the `fn` with all the specified bindings.
10385  */
10386 /* jshint +W101 */
10387 function bind(self, fn) {
10388   var curryArgs = arguments.length > 2 ? sliceArgs(arguments, 2) : [];
10389   if (isFunction(fn) && !(fn instanceof RegExp)) {
10390     return curryArgs.length
10391       ? function() {
10392           return arguments.length
10393             ? fn.apply(self, concat(curryArgs, arguments, 0))
10394             : fn.apply(self, curryArgs);
10395         }
10396       : function() {
10397           return arguments.length
10398             ? fn.apply(self, arguments)
10399             : fn.call(self);
10400         };
10401   } else {
10402     // in IE, native methods are not functions so they cannot be bound (note: they don't need to be)
10403     return fn;
10404   }
10405 }
10406
10407
10408 function toJsonReplacer(key, value) {
10409   var val = value;
10410
10411   if (typeof key === 'string' && key.charAt(0) === '$' && key.charAt(1) === '$') {
10412     val = undefined;
10413   } else if (isWindow(value)) {
10414     val = '$WINDOW';
10415   } else if (value &&  document === value) {
10416     val = '$DOCUMENT';
10417   } else if (isScope(value)) {
10418     val = '$SCOPE';
10419   }
10420
10421   return val;
10422 }
10423
10424
10425 /**
10426  * @ngdoc function
10427  * @name angular.toJson
10428  * @module ng
10429  * @kind function
10430  *
10431  * @description
10432  * Serializes input into a JSON-formatted string. Properties with leading $$ characters will be
10433  * stripped since angular uses this notation internally.
10434  *
10435  * @param {Object|Array|Date|string|number} obj Input to be serialized into JSON.
10436  * @param {boolean|number} [pretty=2] If set to true, the JSON output will contain newlines and whitespace.
10437  *    If set to an integer, the JSON output will contain that many spaces per indentation.
10438  * @returns {string|undefined} JSON-ified string representing `obj`.
10439  */
10440 function toJson(obj, pretty) {
10441   if (typeof obj === 'undefined') return undefined;
10442   if (!isNumber(pretty)) {
10443     pretty = pretty ? 2 : null;
10444   }
10445   return JSON.stringify(obj, toJsonReplacer, pretty);
10446 }
10447
10448
10449 /**
10450  * @ngdoc function
10451  * @name angular.fromJson
10452  * @module ng
10453  * @kind function
10454  *
10455  * @description
10456  * Deserializes a JSON string.
10457  *
10458  * @param {string} json JSON string to deserialize.
10459  * @returns {Object|Array|string|number} Deserialized JSON string.
10460  */
10461 function fromJson(json) {
10462   return isString(json)
10463       ? JSON.parse(json)
10464       : json;
10465 }
10466
10467
10468 function timezoneToOffset(timezone, fallback) {
10469   var requestedTimezoneOffset = Date.parse('Jan 01, 1970 00:00:00 ' + timezone) / 60000;
10470   return isNaN(requestedTimezoneOffset) ? fallback : requestedTimezoneOffset;
10471 }
10472
10473
10474 function addDateMinutes(date, minutes) {
10475   date = new Date(date.getTime());
10476   date.setMinutes(date.getMinutes() + minutes);
10477   return date;
10478 }
10479
10480
10481 function convertTimezoneToLocal(date, timezone, reverse) {
10482   reverse = reverse ? -1 : 1;
10483   var timezoneOffset = timezoneToOffset(timezone, date.getTimezoneOffset());
10484   return addDateMinutes(date, reverse * (timezoneOffset - date.getTimezoneOffset()));
10485 }
10486
10487
10488 /**
10489  * @returns {string} Returns the string representation of the element.
10490  */
10491 function startingTag(element) {
10492   element = jqLite(element).clone();
10493   try {
10494     // turns out IE does not let you set .html() on elements which
10495     // are not allowed to have children. So we just ignore it.
10496     element.empty();
10497   } catch (e) {}
10498   var elemHtml = jqLite('<div>').append(element).html();
10499   try {
10500     return element[0].nodeType === NODE_TYPE_TEXT ? lowercase(elemHtml) :
10501         elemHtml.
10502           match(/^(<[^>]+>)/)[1].
10503           replace(/^<([\w\-]+)/, function(match, nodeName) { return '<' + lowercase(nodeName); });
10504   } catch (e) {
10505     return lowercase(elemHtml);
10506   }
10507
10508 }
10509
10510
10511 /////////////////////////////////////////////////
10512
10513 /**
10514  * Tries to decode the URI component without throwing an exception.
10515  *
10516  * @private
10517  * @param str value potential URI component to check.
10518  * @returns {boolean} True if `value` can be decoded
10519  * with the decodeURIComponent function.
10520  */
10521 function tryDecodeURIComponent(value) {
10522   try {
10523     return decodeURIComponent(value);
10524   } catch (e) {
10525     // Ignore any invalid uri component
10526   }
10527 }
10528
10529
10530 /**
10531  * Parses an escaped url query string into key-value pairs.
10532  * @returns {Object.<string,boolean|Array>}
10533  */
10534 function parseKeyValue(/**string*/keyValue) {
10535   var obj = {};
10536   forEach((keyValue || "").split('&'), function(keyValue) {
10537     var splitPoint, key, val;
10538     if (keyValue) {
10539       key = keyValue = keyValue.replace(/\+/g,'%20');
10540       splitPoint = keyValue.indexOf('=');
10541       if (splitPoint !== -1) {
10542         key = keyValue.substring(0, splitPoint);
10543         val = keyValue.substring(splitPoint + 1);
10544       }
10545       key = tryDecodeURIComponent(key);
10546       if (isDefined(key)) {
10547         val = isDefined(val) ? tryDecodeURIComponent(val) : true;
10548         if (!hasOwnProperty.call(obj, key)) {
10549           obj[key] = val;
10550         } else if (isArray(obj[key])) {
10551           obj[key].push(val);
10552         } else {
10553           obj[key] = [obj[key],val];
10554         }
10555       }
10556     }
10557   });
10558   return obj;
10559 }
10560
10561 function toKeyValue(obj) {
10562   var parts = [];
10563   forEach(obj, function(value, key) {
10564     if (isArray(value)) {
10565       forEach(value, function(arrayValue) {
10566         parts.push(encodeUriQuery(key, true) +
10567                    (arrayValue === true ? '' : '=' + encodeUriQuery(arrayValue, true)));
10568       });
10569     } else {
10570     parts.push(encodeUriQuery(key, true) +
10571                (value === true ? '' : '=' + encodeUriQuery(value, true)));
10572     }
10573   });
10574   return parts.length ? parts.join('&') : '';
10575 }
10576
10577
10578 /**
10579  * We need our custom method because encodeURIComponent is too aggressive and doesn't follow
10580  * http://www.ietf.org/rfc/rfc3986.txt with regards to the character set (pchar) allowed in path
10581  * segments:
10582  *    segment       = *pchar
10583  *    pchar         = unreserved / pct-encoded / sub-delims / ":" / "@"
10584  *    pct-encoded   = "%" HEXDIG HEXDIG
10585  *    unreserved    = ALPHA / DIGIT / "-" / "." / "_" / "~"
10586  *    sub-delims    = "!" / "$" / "&" / "'" / "(" / ")"
10587  *                     / "*" / "+" / "," / ";" / "="
10588  */
10589 function encodeUriSegment(val) {
10590   return encodeUriQuery(val, true).
10591              replace(/%26/gi, '&').
10592              replace(/%3D/gi, '=').
10593              replace(/%2B/gi, '+');
10594 }
10595
10596
10597 /**
10598  * This method is intended for encoding *key* or *value* parts of query component. We need a custom
10599  * method because encodeURIComponent is too aggressive and encodes stuff that doesn't have to be
10600  * encoded per http://tools.ietf.org/html/rfc3986:
10601  *    query       = *( pchar / "/" / "?" )
10602  *    pchar         = unreserved / pct-encoded / sub-delims / ":" / "@"
10603  *    unreserved    = ALPHA / DIGIT / "-" / "." / "_" / "~"
10604  *    pct-encoded   = "%" HEXDIG HEXDIG
10605  *    sub-delims    = "!" / "$" / "&" / "'" / "(" / ")"
10606  *                     / "*" / "+" / "," / ";" / "="
10607  */
10608 function encodeUriQuery(val, pctEncodeSpaces) {
10609   return encodeURIComponent(val).
10610              replace(/%40/gi, '@').
10611              replace(/%3A/gi, ':').
10612              replace(/%24/g, '$').
10613              replace(/%2C/gi, ',').
10614              replace(/%3B/gi, ';').
10615              replace(/%20/g, (pctEncodeSpaces ? '%20' : '+'));
10616 }
10617
10618 var ngAttrPrefixes = ['ng-', 'data-ng-', 'ng:', 'x-ng-'];
10619
10620 function getNgAttribute(element, ngAttr) {
10621   var attr, i, ii = ngAttrPrefixes.length;
10622   for (i = 0; i < ii; ++i) {
10623     attr = ngAttrPrefixes[i] + ngAttr;
10624     if (isString(attr = element.getAttribute(attr))) {
10625       return attr;
10626     }
10627   }
10628   return null;
10629 }
10630
10631 /**
10632  * @ngdoc directive
10633  * @name ngApp
10634  * @module ng
10635  *
10636  * @element ANY
10637  * @param {angular.Module} ngApp an optional application
10638  *   {@link angular.module module} name to load.
10639  * @param {boolean=} ngStrictDi if this attribute is present on the app element, the injector will be
10640  *   created in "strict-di" mode. This means that the application will fail to invoke functions which
10641  *   do not use explicit function annotation (and are thus unsuitable for minification), as described
10642  *   in {@link guide/di the Dependency Injection guide}, and useful debugging info will assist in
10643  *   tracking down the root of these bugs.
10644  *
10645  * @description
10646  *
10647  * Use this directive to **auto-bootstrap** an AngularJS application. The `ngApp` directive
10648  * designates the **root element** of the application and is typically placed near the root element
10649  * of the page - e.g. on the `<body>` or `<html>` tags.
10650  *
10651  * Only one AngularJS application can be auto-bootstrapped per HTML document. The first `ngApp`
10652  * found in the document will be used to define the root element to auto-bootstrap as an
10653  * application. To run multiple applications in an HTML document you must manually bootstrap them using
10654  * {@link angular.bootstrap} instead. AngularJS applications cannot be nested within each other.
10655  *
10656  * You can specify an **AngularJS module** to be used as the root module for the application.  This
10657  * module will be loaded into the {@link auto.$injector} when the application is bootstrapped. It
10658  * should contain the application code needed or have dependencies on other modules that will
10659  * contain the code. See {@link angular.module} for more information.
10660  *
10661  * In the example below if the `ngApp` directive were not placed on the `html` element then the
10662  * document would not be compiled, the `AppController` would not be instantiated and the `{{ a+b }}`
10663  * would not be resolved to `3`.
10664  *
10665  * `ngApp` is the easiest, and most common way to bootstrap an application.
10666  *
10667  <example module="ngAppDemo">
10668    <file name="index.html">
10669    <div ng-controller="ngAppDemoController">
10670      I can add: {{a}} + {{b}} =  {{ a+b }}
10671    </div>
10672    </file>
10673    <file name="script.js">
10674    angular.module('ngAppDemo', []).controller('ngAppDemoController', function($scope) {
10675      $scope.a = 1;
10676      $scope.b = 2;
10677    });
10678    </file>
10679  </example>
10680  *
10681  * Using `ngStrictDi`, you would see something like this:
10682  *
10683  <example ng-app-included="true">
10684    <file name="index.html">
10685    <div ng-app="ngAppStrictDemo" ng-strict-di>
10686        <div ng-controller="GoodController1">
10687            I can add: {{a}} + {{b}} =  {{ a+b }}
10688
10689            <p>This renders because the controller does not fail to
10690               instantiate, by using explicit annotation style (see
10691               script.js for details)
10692            </p>
10693        </div>
10694
10695        <div ng-controller="GoodController2">
10696            Name: <input ng-model="name"><br />
10697            Hello, {{name}}!
10698
10699            <p>This renders because the controller does not fail to
10700               instantiate, by using explicit annotation style
10701               (see script.js for details)
10702            </p>
10703        </div>
10704
10705        <div ng-controller="BadController">
10706            I can add: {{a}} + {{b}} =  {{ a+b }}
10707
10708            <p>The controller could not be instantiated, due to relying
10709               on automatic function annotations (which are disabled in
10710               strict mode). As such, the content of this section is not
10711               interpolated, and there should be an error in your web console.
10712            </p>
10713        </div>
10714    </div>
10715    </file>
10716    <file name="script.js">
10717    angular.module('ngAppStrictDemo', [])
10718      // BadController will fail to instantiate, due to relying on automatic function annotation,
10719      // rather than an explicit annotation
10720      .controller('BadController', function($scope) {
10721        $scope.a = 1;
10722        $scope.b = 2;
10723      })
10724      // Unlike BadController, GoodController1 and GoodController2 will not fail to be instantiated,
10725      // due to using explicit annotations using the array style and $inject property, respectively.
10726      .controller('GoodController1', ['$scope', function($scope) {
10727        $scope.a = 1;
10728        $scope.b = 2;
10729      }])
10730      .controller('GoodController2', GoodController2);
10731      function GoodController2($scope) {
10732        $scope.name = "World";
10733      }
10734      GoodController2.$inject = ['$scope'];
10735    </file>
10736    <file name="style.css">
10737    div[ng-controller] {
10738        margin-bottom: 1em;
10739        -webkit-border-radius: 4px;
10740        border-radius: 4px;
10741        border: 1px solid;
10742        padding: .5em;
10743    }
10744    div[ng-controller^=Good] {
10745        border-color: #d6e9c6;
10746        background-color: #dff0d8;
10747        color: #3c763d;
10748    }
10749    div[ng-controller^=Bad] {
10750        border-color: #ebccd1;
10751        background-color: #f2dede;
10752        color: #a94442;
10753        margin-bottom: 0;
10754    }
10755    </file>
10756  </example>
10757  */
10758 function angularInit(element, bootstrap) {
10759   var appElement,
10760       module,
10761       config = {};
10762
10763   // The element `element` has priority over any other element
10764   forEach(ngAttrPrefixes, function(prefix) {
10765     var name = prefix + 'app';
10766
10767     if (!appElement && element.hasAttribute && element.hasAttribute(name)) {
10768       appElement = element;
10769       module = element.getAttribute(name);
10770     }
10771   });
10772   forEach(ngAttrPrefixes, function(prefix) {
10773     var name = prefix + 'app';
10774     var candidate;
10775
10776     if (!appElement && (candidate = element.querySelector('[' + name.replace(':', '\\:') + ']'))) {
10777       appElement = candidate;
10778       module = candidate.getAttribute(name);
10779     }
10780   });
10781   if (appElement) {
10782     config.strictDi = getNgAttribute(appElement, "strict-di") !== null;
10783     bootstrap(appElement, module ? [module] : [], config);
10784   }
10785 }
10786
10787 /**
10788  * @ngdoc function
10789  * @name angular.bootstrap
10790  * @module ng
10791  * @description
10792  * Use this function to manually start up angular application.
10793  *
10794  * See: {@link guide/bootstrap Bootstrap}
10795  *
10796  * Note that Protractor based end-to-end tests cannot use this function to bootstrap manually.
10797  * They must use {@link ng.directive:ngApp ngApp}.
10798  *
10799  * Angular will detect if it has been loaded into the browser more than once and only allow the
10800  * first loaded script to be bootstrapped and will report a warning to the browser console for
10801  * each of the subsequent scripts. This prevents strange results in applications, where otherwise
10802  * multiple instances of Angular try to work on the DOM.
10803  *
10804  * ```html
10805  * <!doctype html>
10806  * <html>
10807  * <body>
10808  * <div ng-controller="WelcomeController">
10809  *   {{greeting}}
10810  * </div>
10811  *
10812  * <script src="angular.js"></script>
10813  * <script>
10814  *   var app = angular.module('demo', [])
10815  *   .controller('WelcomeController', function($scope) {
10816  *       $scope.greeting = 'Welcome!';
10817  *   });
10818  *   angular.bootstrap(document, ['demo']);
10819  * </script>
10820  * </body>
10821  * </html>
10822  * ```
10823  *
10824  * @param {DOMElement} element DOM element which is the root of angular application.
10825  * @param {Array<String|Function|Array>=} modules an array of modules to load into the application.
10826  *     Each item in the array should be the name of a predefined module or a (DI annotated)
10827  *     function that will be invoked by the injector as a `config` block.
10828  *     See: {@link angular.module modules}
10829  * @param {Object=} config an object for defining configuration options for the application. The
10830  *     following keys are supported:
10831  *
10832  * * `strictDi` - disable automatic function annotation for the application. This is meant to
10833  *   assist in finding bugs which break minified code. Defaults to `false`.
10834  *
10835  * @returns {auto.$injector} Returns the newly created injector for this app.
10836  */
10837 function bootstrap(element, modules, config) {
10838   if (!isObject(config)) config = {};
10839   var defaultConfig = {
10840     strictDi: false
10841   };
10842   config = extend(defaultConfig, config);
10843   var doBootstrap = function() {
10844     element = jqLite(element);
10845
10846     if (element.injector()) {
10847       var tag = (element[0] === document) ? 'document' : startingTag(element);
10848       //Encode angle brackets to prevent input from being sanitized to empty string #8683
10849       throw ngMinErr(
10850           'btstrpd',
10851           "App Already Bootstrapped with this Element '{0}'",
10852           tag.replace(/</,'&lt;').replace(/>/,'&gt;'));
10853     }
10854
10855     modules = modules || [];
10856     modules.unshift(['$provide', function($provide) {
10857       $provide.value('$rootElement', element);
10858     }]);
10859
10860     if (config.debugInfoEnabled) {
10861       // Pushing so that this overrides `debugInfoEnabled` setting defined in user's `modules`.
10862       modules.push(['$compileProvider', function($compileProvider) {
10863         $compileProvider.debugInfoEnabled(true);
10864       }]);
10865     }
10866
10867     modules.unshift('ng');
10868     var injector = createInjector(modules, config.strictDi);
10869     injector.invoke(['$rootScope', '$rootElement', '$compile', '$injector',
10870        function bootstrapApply(scope, element, compile, injector) {
10871         scope.$apply(function() {
10872           element.data('$injector', injector);
10873           compile(element)(scope);
10874         });
10875       }]
10876     );
10877     return injector;
10878   };
10879
10880   var NG_ENABLE_DEBUG_INFO = /^NG_ENABLE_DEBUG_INFO!/;
10881   var NG_DEFER_BOOTSTRAP = /^NG_DEFER_BOOTSTRAP!/;
10882
10883   if (window && NG_ENABLE_DEBUG_INFO.test(window.name)) {
10884     config.debugInfoEnabled = true;
10885     window.name = window.name.replace(NG_ENABLE_DEBUG_INFO, '');
10886   }
10887
10888   if (window && !NG_DEFER_BOOTSTRAP.test(window.name)) {
10889     return doBootstrap();
10890   }
10891
10892   window.name = window.name.replace(NG_DEFER_BOOTSTRAP, '');
10893   angular.resumeBootstrap = function(extraModules) {
10894     forEach(extraModules, function(module) {
10895       modules.push(module);
10896     });
10897     return doBootstrap();
10898   };
10899
10900   if (isFunction(angular.resumeDeferredBootstrap)) {
10901     angular.resumeDeferredBootstrap();
10902   }
10903 }
10904
10905 /**
10906  * @ngdoc function
10907  * @name angular.reloadWithDebugInfo
10908  * @module ng
10909  * @description
10910  * Use this function to reload the current application with debug information turned on.
10911  * This takes precedence over a call to `$compileProvider.debugInfoEnabled(false)`.
10912  *
10913  * See {@link ng.$compileProvider#debugInfoEnabled} for more.
10914  */
10915 function reloadWithDebugInfo() {
10916   window.name = 'NG_ENABLE_DEBUG_INFO!' + window.name;
10917   window.location.reload();
10918 }
10919
10920 /**
10921  * @name angular.getTestability
10922  * @module ng
10923  * @description
10924  * Get the testability service for the instance of Angular on the given
10925  * element.
10926  * @param {DOMElement} element DOM element which is the root of angular application.
10927  */
10928 function getTestability(rootElement) {
10929   var injector = angular.element(rootElement).injector();
10930   if (!injector) {
10931     throw ngMinErr('test',
10932       'no injector found for element argument to getTestability');
10933   }
10934   return injector.get('$$testability');
10935 }
10936
10937 var SNAKE_CASE_REGEXP = /[A-Z]/g;
10938 function snake_case(name, separator) {
10939   separator = separator || '_';
10940   return name.replace(SNAKE_CASE_REGEXP, function(letter, pos) {
10941     return (pos ? separator : '') + letter.toLowerCase();
10942   });
10943 }
10944
10945 var bindJQueryFired = false;
10946 var skipDestroyOnNextJQueryCleanData;
10947 function bindJQuery() {
10948   var originalCleanData;
10949
10950   if (bindJQueryFired) {
10951     return;
10952   }
10953
10954   // bind to jQuery if present;
10955   var jqName = jq();
10956   jQuery = isUndefined(jqName) ? window.jQuery :   // use jQuery (if present)
10957            !jqName             ? undefined     :   // use jqLite
10958                                  window[jqName];   // use jQuery specified by `ngJq`
10959
10960   // Use jQuery if it exists with proper functionality, otherwise default to us.
10961   // Angular 1.2+ requires jQuery 1.7+ for on()/off() support.
10962   // Angular 1.3+ technically requires at least jQuery 2.1+ but it may work with older
10963   // versions. It will not work for sure with jQuery <1.7, though.
10964   if (jQuery && jQuery.fn.on) {
10965     jqLite = jQuery;
10966     extend(jQuery.fn, {
10967       scope: JQLitePrototype.scope,
10968       isolateScope: JQLitePrototype.isolateScope,
10969       controller: JQLitePrototype.controller,
10970       injector: JQLitePrototype.injector,
10971       inheritedData: JQLitePrototype.inheritedData
10972     });
10973
10974     // All nodes removed from the DOM via various jQuery APIs like .remove()
10975     // are passed through jQuery.cleanData. Monkey-patch this method to fire
10976     // the $destroy event on all removed nodes.
10977     originalCleanData = jQuery.cleanData;
10978     jQuery.cleanData = function(elems) {
10979       var events;
10980       if (!skipDestroyOnNextJQueryCleanData) {
10981         for (var i = 0, elem; (elem = elems[i]) != null; i++) {
10982           events = jQuery._data(elem, "events");
10983           if (events && events.$destroy) {
10984             jQuery(elem).triggerHandler('$destroy');
10985           }
10986         }
10987       } else {
10988         skipDestroyOnNextJQueryCleanData = false;
10989       }
10990       originalCleanData(elems);
10991     };
10992   } else {
10993     jqLite = JQLite;
10994   }
10995
10996   angular.element = jqLite;
10997
10998   // Prevent double-proxying.
10999   bindJQueryFired = true;
11000 }
11001
11002 /**
11003  * throw error if the argument is falsy.
11004  */
11005 function assertArg(arg, name, reason) {
11006   if (!arg) {
11007     throw ngMinErr('areq', "Argument '{0}' is {1}", (name || '?'), (reason || "required"));
11008   }
11009   return arg;
11010 }
11011
11012 function assertArgFn(arg, name, acceptArrayAnnotation) {
11013   if (acceptArrayAnnotation && isArray(arg)) {
11014       arg = arg[arg.length - 1];
11015   }
11016
11017   assertArg(isFunction(arg), name, 'not a function, got ' +
11018       (arg && typeof arg === 'object' ? arg.constructor.name || 'Object' : typeof arg));
11019   return arg;
11020 }
11021
11022 /**
11023  * throw error if the name given is hasOwnProperty
11024  * @param  {String} name    the name to test
11025  * @param  {String} context the context in which the name is used, such as module or directive
11026  */
11027 function assertNotHasOwnProperty(name, context) {
11028   if (name === 'hasOwnProperty') {
11029     throw ngMinErr('badname', "hasOwnProperty is not a valid {0} name", context);
11030   }
11031 }
11032
11033 /**
11034  * Return the value accessible from the object by path. Any undefined traversals are ignored
11035  * @param {Object} obj starting object
11036  * @param {String} path path to traverse
11037  * @param {boolean} [bindFnToScope=true]
11038  * @returns {Object} value as accessible by path
11039  */
11040 //TODO(misko): this function needs to be removed
11041 function getter(obj, path, bindFnToScope) {
11042   if (!path) return obj;
11043   var keys = path.split('.');
11044   var key;
11045   var lastInstance = obj;
11046   var len = keys.length;
11047
11048   for (var i = 0; i < len; i++) {
11049     key = keys[i];
11050     if (obj) {
11051       obj = (lastInstance = obj)[key];
11052     }
11053   }
11054   if (!bindFnToScope && isFunction(obj)) {
11055     return bind(lastInstance, obj);
11056   }
11057   return obj;
11058 }
11059
11060 /**
11061  * Return the DOM siblings between the first and last node in the given array.
11062  * @param {Array} array like object
11063  * @returns {Array} the inputted object or a jqLite collection containing the nodes
11064  */
11065 function getBlockNodes(nodes) {
11066   // TODO(perf): update `nodes` instead of creating a new object?
11067   var node = nodes[0];
11068   var endNode = nodes[nodes.length - 1];
11069   var blockNodes;
11070
11071   for (var i = 1; node !== endNode && (node = node.nextSibling); i++) {
11072     if (blockNodes || nodes[i] !== node) {
11073       if (!blockNodes) {
11074         blockNodes = jqLite(slice.call(nodes, 0, i));
11075       }
11076       blockNodes.push(node);
11077     }
11078   }
11079
11080   return blockNodes || nodes;
11081 }
11082
11083
11084 /**
11085  * Creates a new object without a prototype. This object is useful for lookup without having to
11086  * guard against prototypically inherited properties via hasOwnProperty.
11087  *
11088  * Related micro-benchmarks:
11089  * - http://jsperf.com/object-create2
11090  * - http://jsperf.com/proto-map-lookup/2
11091  * - http://jsperf.com/for-in-vs-object-keys2
11092  *
11093  * @returns {Object}
11094  */
11095 function createMap() {
11096   return Object.create(null);
11097 }
11098
11099 var NODE_TYPE_ELEMENT = 1;
11100 var NODE_TYPE_ATTRIBUTE = 2;
11101 var NODE_TYPE_TEXT = 3;
11102 var NODE_TYPE_COMMENT = 8;
11103 var NODE_TYPE_DOCUMENT = 9;
11104 var NODE_TYPE_DOCUMENT_FRAGMENT = 11;
11105
11106 /**
11107  * @ngdoc type
11108  * @name angular.Module
11109  * @module ng
11110  * @description
11111  *
11112  * Interface for configuring angular {@link angular.module modules}.
11113  */
11114
11115 function setupModuleLoader(window) {
11116
11117   var $injectorMinErr = minErr('$injector');
11118   var ngMinErr = minErr('ng');
11119
11120   function ensure(obj, name, factory) {
11121     return obj[name] || (obj[name] = factory());
11122   }
11123
11124   var angular = ensure(window, 'angular', Object);
11125
11126   // We need to expose `angular.$$minErr` to modules such as `ngResource` that reference it during bootstrap
11127   angular.$$minErr = angular.$$minErr || minErr;
11128
11129   return ensure(angular, 'module', function() {
11130     /** @type {Object.<string, angular.Module>} */
11131     var modules = {};
11132
11133     /**
11134      * @ngdoc function
11135      * @name angular.module
11136      * @module ng
11137      * @description
11138      *
11139      * The `angular.module` is a global place for creating, registering and retrieving Angular
11140      * modules.
11141      * All modules (angular core or 3rd party) that should be available to an application must be
11142      * registered using this mechanism.
11143      *
11144      * Passing one argument retrieves an existing {@link angular.Module},
11145      * whereas passing more than one argument creates a new {@link angular.Module}
11146      *
11147      *
11148      * # Module
11149      *
11150      * A module is a collection of services, directives, controllers, filters, and configuration information.
11151      * `angular.module` is used to configure the {@link auto.$injector $injector}.
11152      *
11153      * ```js
11154      * // Create a new module
11155      * var myModule = angular.module('myModule', []);
11156      *
11157      * // register a new service
11158      * myModule.value('appName', 'MyCoolApp');
11159      *
11160      * // configure existing services inside initialization blocks.
11161      * myModule.config(['$locationProvider', function($locationProvider) {
11162      *   // Configure existing providers
11163      *   $locationProvider.hashPrefix('!');
11164      * }]);
11165      * ```
11166      *
11167      * Then you can create an injector and load your modules like this:
11168      *
11169      * ```js
11170      * var injector = angular.injector(['ng', 'myModule'])
11171      * ```
11172      *
11173      * However it's more likely that you'll just use
11174      * {@link ng.directive:ngApp ngApp} or
11175      * {@link angular.bootstrap} to simplify this process for you.
11176      *
11177      * @param {!string} name The name of the module to create or retrieve.
11178      * @param {!Array.<string>=} requires If specified then new module is being created. If
11179      *        unspecified then the module is being retrieved for further configuration.
11180      * @param {Function=} configFn Optional configuration function for the module. Same as
11181      *        {@link angular.Module#config Module#config()}.
11182      * @returns {module} new module with the {@link angular.Module} api.
11183      */
11184     return function module(name, requires, configFn) {
11185       var assertNotHasOwnProperty = function(name, context) {
11186         if (name === 'hasOwnProperty') {
11187           throw ngMinErr('badname', 'hasOwnProperty is not a valid {0} name', context);
11188         }
11189       };
11190
11191       assertNotHasOwnProperty(name, 'module');
11192       if (requires && modules.hasOwnProperty(name)) {
11193         modules[name] = null;
11194       }
11195       return ensure(modules, name, function() {
11196         if (!requires) {
11197           throw $injectorMinErr('nomod', "Module '{0}' is not available! You either misspelled " +
11198              "the module name or forgot to load it. If registering a module ensure that you " +
11199              "specify the dependencies as the second argument.", name);
11200         }
11201
11202         /** @type {!Array.<Array.<*>>} */
11203         var invokeQueue = [];
11204
11205         /** @type {!Array.<Function>} */
11206         var configBlocks = [];
11207
11208         /** @type {!Array.<Function>} */
11209         var runBlocks = [];
11210
11211         var config = invokeLater('$injector', 'invoke', 'push', configBlocks);
11212
11213         /** @type {angular.Module} */
11214         var moduleInstance = {
11215           // Private state
11216           _invokeQueue: invokeQueue,
11217           _configBlocks: configBlocks,
11218           _runBlocks: runBlocks,
11219
11220           /**
11221            * @ngdoc property
11222            * @name angular.Module#requires
11223            * @module ng
11224            *
11225            * @description
11226            * Holds the list of modules which the injector will load before the current module is
11227            * loaded.
11228            */
11229           requires: requires,
11230
11231           /**
11232            * @ngdoc property
11233            * @name angular.Module#name
11234            * @module ng
11235            *
11236            * @description
11237            * Name of the module.
11238            */
11239           name: name,
11240
11241
11242           /**
11243            * @ngdoc method
11244            * @name angular.Module#provider
11245            * @module ng
11246            * @param {string} name service name
11247            * @param {Function} providerType Construction function for creating new instance of the
11248            *                                service.
11249            * @description
11250            * See {@link auto.$provide#provider $provide.provider()}.
11251            */
11252           provider: invokeLaterAndSetModuleName('$provide', 'provider'),
11253
11254           /**
11255            * @ngdoc method
11256            * @name angular.Module#factory
11257            * @module ng
11258            * @param {string} name service name
11259            * @param {Function} providerFunction Function for creating new instance of the service.
11260            * @description
11261            * See {@link auto.$provide#factory $provide.factory()}.
11262            */
11263           factory: invokeLaterAndSetModuleName('$provide', 'factory'),
11264
11265           /**
11266            * @ngdoc method
11267            * @name angular.Module#service
11268            * @module ng
11269            * @param {string} name service name
11270            * @param {Function} constructor A constructor function that will be instantiated.
11271            * @description
11272            * See {@link auto.$provide#service $provide.service()}.
11273            */
11274           service: invokeLaterAndSetModuleName('$provide', 'service'),
11275
11276           /**
11277            * @ngdoc method
11278            * @name angular.Module#value
11279            * @module ng
11280            * @param {string} name service name
11281            * @param {*} object Service instance object.
11282            * @description
11283            * See {@link auto.$provide#value $provide.value()}.
11284            */
11285           value: invokeLater('$provide', 'value'),
11286
11287           /**
11288            * @ngdoc method
11289            * @name angular.Module#constant
11290            * @module ng
11291            * @param {string} name constant name
11292            * @param {*} object Constant value.
11293            * @description
11294            * Because the constants are fixed, they get applied before other provide methods.
11295            * See {@link auto.$provide#constant $provide.constant()}.
11296            */
11297           constant: invokeLater('$provide', 'constant', 'unshift'),
11298
11299            /**
11300            * @ngdoc method
11301            * @name angular.Module#decorator
11302            * @module ng
11303            * @param {string} The name of the service to decorate.
11304            * @param {Function} This function will be invoked when the service needs to be
11305            *                                    instantiated and should return the decorated service instance.
11306            * @description
11307            * See {@link auto.$provide#decorator $provide.decorator()}.
11308            */
11309           decorator: invokeLaterAndSetModuleName('$provide', 'decorator'),
11310
11311           /**
11312            * @ngdoc method
11313            * @name angular.Module#animation
11314            * @module ng
11315            * @param {string} name animation name
11316            * @param {Function} animationFactory Factory function for creating new instance of an
11317            *                                    animation.
11318            * @description
11319            *
11320            * **NOTE**: animations take effect only if the **ngAnimate** module is loaded.
11321            *
11322            *
11323            * Defines an animation hook that can be later used with
11324            * {@link $animate $animate} service and directives that use this service.
11325            *
11326            * ```js
11327            * module.animation('.animation-name', function($inject1, $inject2) {
11328            *   return {
11329            *     eventName : function(element, done) {
11330            *       //code to run the animation
11331            *       //once complete, then run done()
11332            *       return function cancellationFunction(element) {
11333            *         //code to cancel the animation
11334            *       }
11335            *     }
11336            *   }
11337            * })
11338            * ```
11339            *
11340            * See {@link ng.$animateProvider#register $animateProvider.register()} and
11341            * {@link ngAnimate ngAnimate module} for more information.
11342            */
11343           animation: invokeLaterAndSetModuleName('$animateProvider', 'register'),
11344
11345           /**
11346            * @ngdoc method
11347            * @name angular.Module#filter
11348            * @module ng
11349            * @param {string} name Filter name - this must be a valid angular expression identifier
11350            * @param {Function} filterFactory Factory function for creating new instance of filter.
11351            * @description
11352            * See {@link ng.$filterProvider#register $filterProvider.register()}.
11353            *
11354            * <div class="alert alert-warning">
11355            * **Note:** Filter names must be valid angular {@link expression} identifiers, such as `uppercase` or `orderBy`.
11356            * Names with special characters, such as hyphens and dots, are not allowed. If you wish to namespace
11357            * your filters, then you can use capitalization (`myappSubsectionFilterx`) or underscores
11358            * (`myapp_subsection_filterx`).
11359            * </div>
11360            */
11361           filter: invokeLaterAndSetModuleName('$filterProvider', 'register'),
11362
11363           /**
11364            * @ngdoc method
11365            * @name angular.Module#controller
11366            * @module ng
11367            * @param {string|Object} name Controller name, or an object map of controllers where the
11368            *    keys are the names and the values are the constructors.
11369            * @param {Function} constructor Controller constructor function.
11370            * @description
11371            * See {@link ng.$controllerProvider#register $controllerProvider.register()}.
11372            */
11373           controller: invokeLaterAndSetModuleName('$controllerProvider', 'register'),
11374
11375           /**
11376            * @ngdoc method
11377            * @name angular.Module#directive
11378            * @module ng
11379            * @param {string|Object} name Directive name, or an object map of directives where the
11380            *    keys are the names and the values are the factories.
11381            * @param {Function} directiveFactory Factory function for creating new instance of
11382            * directives.
11383            * @description
11384            * See {@link ng.$compileProvider#directive $compileProvider.directive()}.
11385            */
11386           directive: invokeLaterAndSetModuleName('$compileProvider', 'directive'),
11387
11388           /**
11389            * @ngdoc method
11390            * @name angular.Module#config
11391            * @module ng
11392            * @param {Function} configFn Execute this function on module load. Useful for service
11393            *    configuration.
11394            * @description
11395            * Use this method to register work which needs to be performed on module loading.
11396            * For more about how to configure services, see
11397            * {@link providers#provider-recipe Provider Recipe}.
11398            */
11399           config: config,
11400
11401           /**
11402            * @ngdoc method
11403            * @name angular.Module#run
11404            * @module ng
11405            * @param {Function} initializationFn Execute this function after injector creation.
11406            *    Useful for application initialization.
11407            * @description
11408            * Use this method to register work which should be performed when the injector is done
11409            * loading all modules.
11410            */
11411           run: function(block) {
11412             runBlocks.push(block);
11413             return this;
11414           }
11415         };
11416
11417         if (configFn) {
11418           config(configFn);
11419         }
11420
11421         return moduleInstance;
11422
11423         /**
11424          * @param {string} provider
11425          * @param {string} method
11426          * @param {String=} insertMethod
11427          * @returns {angular.Module}
11428          */
11429         function invokeLater(provider, method, insertMethod, queue) {
11430           if (!queue) queue = invokeQueue;
11431           return function() {
11432             queue[insertMethod || 'push']([provider, method, arguments]);
11433             return moduleInstance;
11434           };
11435         }
11436
11437         /**
11438          * @param {string} provider
11439          * @param {string} method
11440          * @returns {angular.Module}
11441          */
11442         function invokeLaterAndSetModuleName(provider, method) {
11443           return function(recipeName, factoryFunction) {
11444             if (factoryFunction && isFunction(factoryFunction)) factoryFunction.$$moduleName = name;
11445             invokeQueue.push([provider, method, arguments]);
11446             return moduleInstance;
11447           };
11448         }
11449       });
11450     };
11451   });
11452
11453 }
11454
11455 /* global: toDebugString: true */
11456
11457 function serializeObject(obj) {
11458   var seen = [];
11459
11460   return JSON.stringify(obj, function(key, val) {
11461     val = toJsonReplacer(key, val);
11462     if (isObject(val)) {
11463
11464       if (seen.indexOf(val) >= 0) return '...';
11465
11466       seen.push(val);
11467     }
11468     return val;
11469   });
11470 }
11471
11472 function toDebugString(obj) {
11473   if (typeof obj === 'function') {
11474     return obj.toString().replace(/ \{[\s\S]*$/, '');
11475   } else if (isUndefined(obj)) {
11476     return 'undefined';
11477   } else if (typeof obj !== 'string') {
11478     return serializeObject(obj);
11479   }
11480   return obj;
11481 }
11482
11483 /* global angularModule: true,
11484   version: true,
11485
11486   $CompileProvider,
11487
11488   htmlAnchorDirective,
11489   inputDirective,
11490   inputDirective,
11491   formDirective,
11492   scriptDirective,
11493   selectDirective,
11494   styleDirective,
11495   optionDirective,
11496   ngBindDirective,
11497   ngBindHtmlDirective,
11498   ngBindTemplateDirective,
11499   ngClassDirective,
11500   ngClassEvenDirective,
11501   ngClassOddDirective,
11502   ngCloakDirective,
11503   ngControllerDirective,
11504   ngFormDirective,
11505   ngHideDirective,
11506   ngIfDirective,
11507   ngIncludeDirective,
11508   ngIncludeFillContentDirective,
11509   ngInitDirective,
11510   ngNonBindableDirective,
11511   ngPluralizeDirective,
11512   ngRepeatDirective,
11513   ngShowDirective,
11514   ngStyleDirective,
11515   ngSwitchDirective,
11516   ngSwitchWhenDirective,
11517   ngSwitchDefaultDirective,
11518   ngOptionsDirective,
11519   ngTranscludeDirective,
11520   ngModelDirective,
11521   ngListDirective,
11522   ngChangeDirective,
11523   patternDirective,
11524   patternDirective,
11525   requiredDirective,
11526   requiredDirective,
11527   minlengthDirective,
11528   minlengthDirective,
11529   maxlengthDirective,
11530   maxlengthDirective,
11531   ngValueDirective,
11532   ngModelOptionsDirective,
11533   ngAttributeAliasDirectives,
11534   ngEventDirectives,
11535
11536   $AnchorScrollProvider,
11537   $AnimateProvider,
11538   $CoreAnimateCssProvider,
11539   $$CoreAnimateQueueProvider,
11540   $$CoreAnimateRunnerProvider,
11541   $BrowserProvider,
11542   $CacheFactoryProvider,
11543   $ControllerProvider,
11544   $DocumentProvider,
11545   $ExceptionHandlerProvider,
11546   $FilterProvider,
11547   $$ForceReflowProvider,
11548   $InterpolateProvider,
11549   $IntervalProvider,
11550   $$HashMapProvider,
11551   $HttpProvider,
11552   $HttpParamSerializerProvider,
11553   $HttpParamSerializerJQLikeProvider,
11554   $HttpBackendProvider,
11555   $xhrFactoryProvider,
11556   $LocationProvider,
11557   $LogProvider,
11558   $ParseProvider,
11559   $RootScopeProvider,
11560   $QProvider,
11561   $$QProvider,
11562   $$SanitizeUriProvider,
11563   $SceProvider,
11564   $SceDelegateProvider,
11565   $SnifferProvider,
11566   $TemplateCacheProvider,
11567   $TemplateRequestProvider,
11568   $$TestabilityProvider,
11569   $TimeoutProvider,
11570   $$RAFProvider,
11571   $WindowProvider,
11572   $$jqLiteProvider,
11573   $$CookieReaderProvider
11574 */
11575
11576
11577 /**
11578  * @ngdoc object
11579  * @name angular.version
11580  * @module ng
11581  * @description
11582  * An object that contains information about the current AngularJS version.
11583  *
11584  * This object has the following properties:
11585  *
11586  * - `full` – `{string}` – Full version string, such as "0.9.18".
11587  * - `major` – `{number}` – Major version number, such as "0".
11588  * - `minor` – `{number}` – Minor version number, such as "9".
11589  * - `dot` – `{number}` – Dot version number, such as "18".
11590  * - `codeName` – `{string}` – Code name of the release, such as "jiggling-armfat".
11591  */
11592 var version = {
11593   full: '1.4.8',    // all of these placeholder strings will be replaced by grunt's
11594   major: 1,    // package task
11595   minor: 4,
11596   dot: 8,
11597   codeName: 'ice-manipulation'
11598 };
11599
11600
11601 function publishExternalAPI(angular) {
11602   extend(angular, {
11603     'bootstrap': bootstrap,
11604     'copy': copy,
11605     'extend': extend,
11606     'merge': merge,
11607     'equals': equals,
11608     'element': jqLite,
11609     'forEach': forEach,
11610     'injector': createInjector,
11611     'noop': noop,
11612     'bind': bind,
11613     'toJson': toJson,
11614     'fromJson': fromJson,
11615     'identity': identity,
11616     'isUndefined': isUndefined,
11617     'isDefined': isDefined,
11618     'isString': isString,
11619     'isFunction': isFunction,
11620     'isObject': isObject,
11621     'isNumber': isNumber,
11622     'isElement': isElement,
11623     'isArray': isArray,
11624     'version': version,
11625     'isDate': isDate,
11626     'lowercase': lowercase,
11627     'uppercase': uppercase,
11628     'callbacks': {counter: 0},
11629     'getTestability': getTestability,
11630     '$$minErr': minErr,
11631     '$$csp': csp,
11632     'reloadWithDebugInfo': reloadWithDebugInfo
11633   });
11634
11635   angularModule = setupModuleLoader(window);
11636
11637   angularModule('ng', ['ngLocale'], ['$provide',
11638     function ngModule($provide) {
11639       // $$sanitizeUriProvider needs to be before $compileProvider as it is used by it.
11640       $provide.provider({
11641         $$sanitizeUri: $$SanitizeUriProvider
11642       });
11643       $provide.provider('$compile', $CompileProvider).
11644         directive({
11645             a: htmlAnchorDirective,
11646             input: inputDirective,
11647             textarea: inputDirective,
11648             form: formDirective,
11649             script: scriptDirective,
11650             select: selectDirective,
11651             style: styleDirective,
11652             option: optionDirective,
11653             ngBind: ngBindDirective,
11654             ngBindHtml: ngBindHtmlDirective,
11655             ngBindTemplate: ngBindTemplateDirective,
11656             ngClass: ngClassDirective,
11657             ngClassEven: ngClassEvenDirective,
11658             ngClassOdd: ngClassOddDirective,
11659             ngCloak: ngCloakDirective,
11660             ngController: ngControllerDirective,
11661             ngForm: ngFormDirective,
11662             ngHide: ngHideDirective,
11663             ngIf: ngIfDirective,
11664             ngInclude: ngIncludeDirective,
11665             ngInit: ngInitDirective,
11666             ngNonBindable: ngNonBindableDirective,
11667             ngPluralize: ngPluralizeDirective,
11668             ngRepeat: ngRepeatDirective,
11669             ngShow: ngShowDirective,
11670             ngStyle: ngStyleDirective,
11671             ngSwitch: ngSwitchDirective,
11672             ngSwitchWhen: ngSwitchWhenDirective,
11673             ngSwitchDefault: ngSwitchDefaultDirective,
11674             ngOptions: ngOptionsDirective,
11675             ngTransclude: ngTranscludeDirective,
11676             ngModel: ngModelDirective,
11677             ngList: ngListDirective,
11678             ngChange: ngChangeDirective,
11679             pattern: patternDirective,
11680             ngPattern: patternDirective,
11681             required: requiredDirective,
11682             ngRequired: requiredDirective,
11683             minlength: minlengthDirective,
11684             ngMinlength: minlengthDirective,
11685             maxlength: maxlengthDirective,
11686             ngMaxlength: maxlengthDirective,
11687             ngValue: ngValueDirective,
11688             ngModelOptions: ngModelOptionsDirective
11689         }).
11690         directive({
11691           ngInclude: ngIncludeFillContentDirective
11692         }).
11693         directive(ngAttributeAliasDirectives).
11694         directive(ngEventDirectives);
11695       $provide.provider({
11696         $anchorScroll: $AnchorScrollProvider,
11697         $animate: $AnimateProvider,
11698         $animateCss: $CoreAnimateCssProvider,
11699         $$animateQueue: $$CoreAnimateQueueProvider,
11700         $$AnimateRunner: $$CoreAnimateRunnerProvider,
11701         $browser: $BrowserProvider,
11702         $cacheFactory: $CacheFactoryProvider,
11703         $controller: $ControllerProvider,
11704         $document: $DocumentProvider,
11705         $exceptionHandler: $ExceptionHandlerProvider,
11706         $filter: $FilterProvider,
11707         $$forceReflow: $$ForceReflowProvider,
11708         $interpolate: $InterpolateProvider,
11709         $interval: $IntervalProvider,
11710         $http: $HttpProvider,
11711         $httpParamSerializer: $HttpParamSerializerProvider,
11712         $httpParamSerializerJQLike: $HttpParamSerializerJQLikeProvider,
11713         $httpBackend: $HttpBackendProvider,
11714         $xhrFactory: $xhrFactoryProvider,
11715         $location: $LocationProvider,
11716         $log: $LogProvider,
11717         $parse: $ParseProvider,
11718         $rootScope: $RootScopeProvider,
11719         $q: $QProvider,
11720         $$q: $$QProvider,
11721         $sce: $SceProvider,
11722         $sceDelegate: $SceDelegateProvider,
11723         $sniffer: $SnifferProvider,
11724         $templateCache: $TemplateCacheProvider,
11725         $templateRequest: $TemplateRequestProvider,
11726         $$testability: $$TestabilityProvider,
11727         $timeout: $TimeoutProvider,
11728         $window: $WindowProvider,
11729         $$rAF: $$RAFProvider,
11730         $$jqLite: $$jqLiteProvider,
11731         $$HashMap: $$HashMapProvider,
11732         $$cookieReader: $$CookieReaderProvider
11733       });
11734     }
11735   ]);
11736 }
11737
11738 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
11739  *     Any commits to this file should be reviewed with security in mind.  *
11740  *   Changes to this file can potentially create security vulnerabilities. *
11741  *          An approval from 2 Core members with history of modifying      *
11742  *                         this file is required.                          *
11743  *                                                                         *
11744  *  Does the change somehow allow for arbitrary javascript to be executed? *
11745  *    Or allows for someone to change the prototype of built-in objects?   *
11746  *     Or gives undesired access to variables likes document or window?    *
11747  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
11748
11749 /* global JQLitePrototype: true,
11750   addEventListenerFn: true,
11751   removeEventListenerFn: true,
11752   BOOLEAN_ATTR: true,
11753   ALIASED_ATTR: true,
11754 */
11755
11756 //////////////////////////////////
11757 //JQLite
11758 //////////////////////////////////
11759
11760 /**
11761  * @ngdoc function
11762  * @name angular.element
11763  * @module ng
11764  * @kind function
11765  *
11766  * @description
11767  * Wraps a raw DOM element or HTML string as a [jQuery](http://jquery.com) element.
11768  *
11769  * If jQuery is available, `angular.element` is an alias for the
11770  * [jQuery](http://api.jquery.com/jQuery/) function. If jQuery is not available, `angular.element`
11771  * delegates to Angular's built-in subset of jQuery, called "jQuery lite" or "jqLite."
11772  *
11773  * <div class="alert alert-success">jqLite is a tiny, API-compatible subset of jQuery that allows
11774  * Angular to manipulate the DOM in a cross-browser compatible way. **jqLite** implements only the most
11775  * commonly needed functionality with the goal of having a very small footprint.</div>
11776  *
11777  * To use `jQuery`, simply ensure it is loaded before the `angular.js` file.
11778  *
11779  * <div class="alert">**Note:** all element references in Angular are always wrapped with jQuery or
11780  * jqLite; they are never raw DOM references.</div>
11781  *
11782  * ## Angular's jqLite
11783  * jqLite provides only the following jQuery methods:
11784  *
11785  * - [`addClass()`](http://api.jquery.com/addClass/)
11786  * - [`after()`](http://api.jquery.com/after/)
11787  * - [`append()`](http://api.jquery.com/append/)
11788  * - [`attr()`](http://api.jquery.com/attr/) - Does not support functions as parameters
11789  * - [`bind()`](http://api.jquery.com/bind/) - Does not support namespaces, selectors or eventData
11790  * - [`children()`](http://api.jquery.com/children/) - Does not support selectors
11791  * - [`clone()`](http://api.jquery.com/clone/)
11792  * - [`contents()`](http://api.jquery.com/contents/)
11793  * - [`css()`](http://api.jquery.com/css/) - Only retrieves inline-styles, does not call `getComputedStyle()`. As a setter, does not convert numbers to strings or append 'px'.
11794  * - [`data()`](http://api.jquery.com/data/)
11795  * - [`detach()`](http://api.jquery.com/detach/)
11796  * - [`empty()`](http://api.jquery.com/empty/)
11797  * - [`eq()`](http://api.jquery.com/eq/)
11798  * - [`find()`](http://api.jquery.com/find/) - Limited to lookups by tag name
11799  * - [`hasClass()`](http://api.jquery.com/hasClass/)
11800  * - [`html()`](http://api.jquery.com/html/)
11801  * - [`next()`](http://api.jquery.com/next/) - Does not support selectors
11802  * - [`on()`](http://api.jquery.com/on/) - Does not support namespaces, selectors or eventData
11803  * - [`off()`](http://api.jquery.com/off/) - Does not support namespaces, selectors or event object as parameter
11804  * - [`one()`](http://api.jquery.com/one/) - Does not support namespaces or selectors
11805  * - [`parent()`](http://api.jquery.com/parent/) - Does not support selectors
11806  * - [`prepend()`](http://api.jquery.com/prepend/)
11807  * - [`prop()`](http://api.jquery.com/prop/)
11808  * - [`ready()`](http://api.jquery.com/ready/)
11809  * - [`remove()`](http://api.jquery.com/remove/)
11810  * - [`removeAttr()`](http://api.jquery.com/removeAttr/)
11811  * - [`removeClass()`](http://api.jquery.com/removeClass/)
11812  * - [`removeData()`](http://api.jquery.com/removeData/)
11813  * - [`replaceWith()`](http://api.jquery.com/replaceWith/)
11814  * - [`text()`](http://api.jquery.com/text/)
11815  * - [`toggleClass()`](http://api.jquery.com/toggleClass/)
11816  * - [`triggerHandler()`](http://api.jquery.com/triggerHandler/) - Passes a dummy event object to handlers.
11817  * - [`unbind()`](http://api.jquery.com/unbind/) - Does not support namespaces or event object as parameter
11818  * - [`val()`](http://api.jquery.com/val/)
11819  * - [`wrap()`](http://api.jquery.com/wrap/)
11820  *
11821  * ## jQuery/jqLite Extras
11822  * Angular also provides the following additional methods and events to both jQuery and jqLite:
11823  *
11824  * ### Events
11825  * - `$destroy` - AngularJS intercepts all jqLite/jQuery's DOM destruction apis and fires this event
11826  *    on all DOM nodes being removed.  This can be used to clean up any 3rd party bindings to the DOM
11827  *    element before it is removed.
11828  *
11829  * ### Methods
11830  * - `controller(name)` - retrieves the controller of the current element or its parent. By default
11831  *   retrieves controller associated with the `ngController` directive. If `name` is provided as
11832  *   camelCase directive name, then the controller for this directive will be retrieved (e.g.
11833  *   `'ngModel'`).
11834  * - `injector()` - retrieves the injector of the current element or its parent.
11835  * - `scope()` - retrieves the {@link ng.$rootScope.Scope scope} of the current
11836  *   element or its parent. Requires {@link guide/production#disabling-debug-data Debug Data} to
11837  *   be enabled.
11838  * - `isolateScope()` - retrieves an isolate {@link ng.$rootScope.Scope scope} if one is attached directly to the
11839  *   current element. This getter should be used only on elements that contain a directive which starts a new isolate
11840  *   scope. Calling `scope()` on this element always returns the original non-isolate scope.
11841  *   Requires {@link guide/production#disabling-debug-data Debug Data} to be enabled.
11842  * - `inheritedData()` - same as `data()`, but walks up the DOM until a value is found or the top
11843  *   parent element is reached.
11844  *
11845  * @param {string|DOMElement} element HTML string or DOMElement to be wrapped into jQuery.
11846  * @returns {Object} jQuery object.
11847  */
11848
11849 JQLite.expando = 'ng339';
11850
11851 var jqCache = JQLite.cache = {},
11852     jqId = 1,
11853     addEventListenerFn = function(element, type, fn) {
11854       element.addEventListener(type, fn, false);
11855     },
11856     removeEventListenerFn = function(element, type, fn) {
11857       element.removeEventListener(type, fn, false);
11858     };
11859
11860 /*
11861  * !!! This is an undocumented "private" function !!!
11862  */
11863 JQLite._data = function(node) {
11864   //jQuery always returns an object on cache miss
11865   return this.cache[node[this.expando]] || {};
11866 };
11867
11868 function jqNextId() { return ++jqId; }
11869
11870
11871 var SPECIAL_CHARS_REGEXP = /([\:\-\_]+(.))/g;
11872 var MOZ_HACK_REGEXP = /^moz([A-Z])/;
11873 var MOUSE_EVENT_MAP= { mouseleave: "mouseout", mouseenter: "mouseover"};
11874 var jqLiteMinErr = minErr('jqLite');
11875
11876 /**
11877  * Converts snake_case to camelCase.
11878  * Also there is special case for Moz prefix starting with upper case letter.
11879  * @param name Name to normalize
11880  */
11881 function camelCase(name) {
11882   return name.
11883     replace(SPECIAL_CHARS_REGEXP, function(_, separator, letter, offset) {
11884       return offset ? letter.toUpperCase() : letter;
11885     }).
11886     replace(MOZ_HACK_REGEXP, 'Moz$1');
11887 }
11888
11889 var SINGLE_TAG_REGEXP = /^<([\w-]+)\s*\/?>(?:<\/\1>|)$/;
11890 var HTML_REGEXP = /<|&#?\w+;/;
11891 var TAG_NAME_REGEXP = /<([\w:-]+)/;
11892 var XHTML_TAG_REGEXP = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:-]+)[^>]*)\/>/gi;
11893
11894 var wrapMap = {
11895   'option': [1, '<select multiple="multiple">', '</select>'],
11896
11897   'thead': [1, '<table>', '</table>'],
11898   'col': [2, '<table><colgroup>', '</colgroup></table>'],
11899   'tr': [2, '<table><tbody>', '</tbody></table>'],
11900   'td': [3, '<table><tbody><tr>', '</tr></tbody></table>'],
11901   '_default': [0, "", ""]
11902 };
11903
11904 wrapMap.optgroup = wrapMap.option;
11905 wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
11906 wrapMap.th = wrapMap.td;
11907
11908
11909 function jqLiteIsTextNode(html) {
11910   return !HTML_REGEXP.test(html);
11911 }
11912
11913 function jqLiteAcceptsData(node) {
11914   // The window object can accept data but has no nodeType
11915   // Otherwise we are only interested in elements (1) and documents (9)
11916   var nodeType = node.nodeType;
11917   return nodeType === NODE_TYPE_ELEMENT || !nodeType || nodeType === NODE_TYPE_DOCUMENT;
11918 }
11919
11920 function jqLiteHasData(node) {
11921   for (var key in jqCache[node.ng339]) {
11922     return true;
11923   }
11924   return false;
11925 }
11926
11927 function jqLiteBuildFragment(html, context) {
11928   var tmp, tag, wrap,
11929       fragment = context.createDocumentFragment(),
11930       nodes = [], i;
11931
11932   if (jqLiteIsTextNode(html)) {
11933     // Convert non-html into a text node
11934     nodes.push(context.createTextNode(html));
11935   } else {
11936     // Convert html into DOM nodes
11937     tmp = tmp || fragment.appendChild(context.createElement("div"));
11938     tag = (TAG_NAME_REGEXP.exec(html) || ["", ""])[1].toLowerCase();
11939     wrap = wrapMap[tag] || wrapMap._default;
11940     tmp.innerHTML = wrap[1] + html.replace(XHTML_TAG_REGEXP, "<$1></$2>") + wrap[2];
11941
11942     // Descend through wrappers to the right content
11943     i = wrap[0];
11944     while (i--) {
11945       tmp = tmp.lastChild;
11946     }
11947
11948     nodes = concat(nodes, tmp.childNodes);
11949
11950     tmp = fragment.firstChild;
11951     tmp.textContent = "";
11952   }
11953
11954   // Remove wrapper from fragment
11955   fragment.textContent = "";
11956   fragment.innerHTML = ""; // Clear inner HTML
11957   forEach(nodes, function(node) {
11958     fragment.appendChild(node);
11959   });
11960
11961   return fragment;
11962 }
11963
11964 function jqLiteParseHTML(html, context) {
11965   context = context || document;
11966   var parsed;
11967
11968   if ((parsed = SINGLE_TAG_REGEXP.exec(html))) {
11969     return [context.createElement(parsed[1])];
11970   }
11971
11972   if ((parsed = jqLiteBuildFragment(html, context))) {
11973     return parsed.childNodes;
11974   }
11975
11976   return [];
11977 }
11978
11979
11980 // IE9-11 has no method "contains" in SVG element and in Node.prototype. Bug #10259.
11981 var jqLiteContains = Node.prototype.contains || function(arg) {
11982   // jshint bitwise: false
11983   return !!(this.compareDocumentPosition(arg) & 16);
11984   // jshint bitwise: true
11985 };
11986
11987 /////////////////////////////////////////////
11988 function JQLite(element) {
11989   if (element instanceof JQLite) {
11990     return element;
11991   }
11992
11993   var argIsString;
11994
11995   if (isString(element)) {
11996     element = trim(element);
11997     argIsString = true;
11998   }
11999   if (!(this instanceof JQLite)) {
12000     if (argIsString && element.charAt(0) != '<') {
12001       throw jqLiteMinErr('nosel', 'Looking up elements via selectors is not supported by jqLite! See: http://docs.angularjs.org/api/angular.element');
12002     }
12003     return new JQLite(element);
12004   }
12005
12006   if (argIsString) {
12007     jqLiteAddNodes(this, jqLiteParseHTML(element));
12008   } else {
12009     jqLiteAddNodes(this, element);
12010   }
12011 }
12012
12013 function jqLiteClone(element) {
12014   return element.cloneNode(true);
12015 }
12016
12017 function jqLiteDealoc(element, onlyDescendants) {
12018   if (!onlyDescendants) jqLiteRemoveData(element);
12019
12020   if (element.querySelectorAll) {
12021     var descendants = element.querySelectorAll('*');
12022     for (var i = 0, l = descendants.length; i < l; i++) {
12023       jqLiteRemoveData(descendants[i]);
12024     }
12025   }
12026 }
12027
12028 function jqLiteOff(element, type, fn, unsupported) {
12029   if (isDefined(unsupported)) throw jqLiteMinErr('offargs', 'jqLite#off() does not support the `selector` argument');
12030
12031   var expandoStore = jqLiteExpandoStore(element);
12032   var events = expandoStore && expandoStore.events;
12033   var handle = expandoStore && expandoStore.handle;
12034
12035   if (!handle) return; //no listeners registered
12036
12037   if (!type) {
12038     for (type in events) {
12039       if (type !== '$destroy') {
12040         removeEventListenerFn(element, type, handle);
12041       }
12042       delete events[type];
12043     }
12044   } else {
12045
12046     var removeHandler = function(type) {
12047       var listenerFns = events[type];
12048       if (isDefined(fn)) {
12049         arrayRemove(listenerFns || [], fn);
12050       }
12051       if (!(isDefined(fn) && listenerFns && listenerFns.length > 0)) {
12052         removeEventListenerFn(element, type, handle);
12053         delete events[type];
12054       }
12055     };
12056
12057     forEach(type.split(' '), function(type) {
12058       removeHandler(type);
12059       if (MOUSE_EVENT_MAP[type]) {
12060         removeHandler(MOUSE_EVENT_MAP[type]);
12061       }
12062     });
12063   }
12064 }
12065
12066 function jqLiteRemoveData(element, name) {
12067   var expandoId = element.ng339;
12068   var expandoStore = expandoId && jqCache[expandoId];
12069
12070   if (expandoStore) {
12071     if (name) {
12072       delete expandoStore.data[name];
12073       return;
12074     }
12075
12076     if (expandoStore.handle) {
12077       if (expandoStore.events.$destroy) {
12078         expandoStore.handle({}, '$destroy');
12079       }
12080       jqLiteOff(element);
12081     }
12082     delete jqCache[expandoId];
12083     element.ng339 = undefined; // don't delete DOM expandos. IE and Chrome don't like it
12084   }
12085 }
12086
12087
12088 function jqLiteExpandoStore(element, createIfNecessary) {
12089   var expandoId = element.ng339,
12090       expandoStore = expandoId && jqCache[expandoId];
12091
12092   if (createIfNecessary && !expandoStore) {
12093     element.ng339 = expandoId = jqNextId();
12094     expandoStore = jqCache[expandoId] = {events: {}, data: {}, handle: undefined};
12095   }
12096
12097   return expandoStore;
12098 }
12099
12100
12101 function jqLiteData(element, key, value) {
12102   if (jqLiteAcceptsData(element)) {
12103
12104     var isSimpleSetter = isDefined(value);
12105     var isSimpleGetter = !isSimpleSetter && key && !isObject(key);
12106     var massGetter = !key;
12107     var expandoStore = jqLiteExpandoStore(element, !isSimpleGetter);
12108     var data = expandoStore && expandoStore.data;
12109
12110     if (isSimpleSetter) { // data('key', value)
12111       data[key] = value;
12112     } else {
12113       if (massGetter) {  // data()
12114         return data;
12115       } else {
12116         if (isSimpleGetter) { // data('key')
12117           // don't force creation of expandoStore if it doesn't exist yet
12118           return data && data[key];
12119         } else { // mass-setter: data({key1: val1, key2: val2})
12120           extend(data, key);
12121         }
12122       }
12123     }
12124   }
12125 }
12126
12127 function jqLiteHasClass(element, selector) {
12128   if (!element.getAttribute) return false;
12129   return ((" " + (element.getAttribute('class') || '') + " ").replace(/[\n\t]/g, " ").
12130       indexOf(" " + selector + " ") > -1);
12131 }
12132
12133 function jqLiteRemoveClass(element, cssClasses) {
12134   if (cssClasses && element.setAttribute) {
12135     forEach(cssClasses.split(' '), function(cssClass) {
12136       element.setAttribute('class', trim(
12137           (" " + (element.getAttribute('class') || '') + " ")
12138           .replace(/[\n\t]/g, " ")
12139           .replace(" " + trim(cssClass) + " ", " "))
12140       );
12141     });
12142   }
12143 }
12144
12145 function jqLiteAddClass(element, cssClasses) {
12146   if (cssClasses && element.setAttribute) {
12147     var existingClasses = (' ' + (element.getAttribute('class') || '') + ' ')
12148                             .replace(/[\n\t]/g, " ");
12149
12150     forEach(cssClasses.split(' '), function(cssClass) {
12151       cssClass = trim(cssClass);
12152       if (existingClasses.indexOf(' ' + cssClass + ' ') === -1) {
12153         existingClasses += cssClass + ' ';
12154       }
12155     });
12156
12157     element.setAttribute('class', trim(existingClasses));
12158   }
12159 }
12160
12161
12162 function jqLiteAddNodes(root, elements) {
12163   // THIS CODE IS VERY HOT. Don't make changes without benchmarking.
12164
12165   if (elements) {
12166
12167     // if a Node (the most common case)
12168     if (elements.nodeType) {
12169       root[root.length++] = elements;
12170     } else {
12171       var length = elements.length;
12172
12173       // if an Array or NodeList and not a Window
12174       if (typeof length === 'number' && elements.window !== elements) {
12175         if (length) {
12176           for (var i = 0; i < length; i++) {
12177             root[root.length++] = elements[i];
12178           }
12179         }
12180       } else {
12181         root[root.length++] = elements;
12182       }
12183     }
12184   }
12185 }
12186
12187
12188 function jqLiteController(element, name) {
12189   return jqLiteInheritedData(element, '$' + (name || 'ngController') + 'Controller');
12190 }
12191
12192 function jqLiteInheritedData(element, name, value) {
12193   // if element is the document object work with the html element instead
12194   // this makes $(document).scope() possible
12195   if (element.nodeType == NODE_TYPE_DOCUMENT) {
12196     element = element.documentElement;
12197   }
12198   var names = isArray(name) ? name : [name];
12199
12200   while (element) {
12201     for (var i = 0, ii = names.length; i < ii; i++) {
12202       if (isDefined(value = jqLite.data(element, names[i]))) return value;
12203     }
12204
12205     // If dealing with a document fragment node with a host element, and no parent, use the host
12206     // element as the parent. This enables directives within a Shadow DOM or polyfilled Shadow DOM
12207     // to lookup parent controllers.
12208     element = element.parentNode || (element.nodeType === NODE_TYPE_DOCUMENT_FRAGMENT && element.host);
12209   }
12210 }
12211
12212 function jqLiteEmpty(element) {
12213   jqLiteDealoc(element, true);
12214   while (element.firstChild) {
12215     element.removeChild(element.firstChild);
12216   }
12217 }
12218
12219 function jqLiteRemove(element, keepData) {
12220   if (!keepData) jqLiteDealoc(element);
12221   var parent = element.parentNode;
12222   if (parent) parent.removeChild(element);
12223 }
12224
12225
12226 function jqLiteDocumentLoaded(action, win) {
12227   win = win || window;
12228   if (win.document.readyState === 'complete') {
12229     // Force the action to be run async for consistent behaviour
12230     // from the action's point of view
12231     // i.e. it will definitely not be in a $apply
12232     win.setTimeout(action);
12233   } else {
12234     // No need to unbind this handler as load is only ever called once
12235     jqLite(win).on('load', action);
12236   }
12237 }
12238
12239 //////////////////////////////////////////
12240 // Functions which are declared directly.
12241 //////////////////////////////////////////
12242 var JQLitePrototype = JQLite.prototype = {
12243   ready: function(fn) {
12244     var fired = false;
12245
12246     function trigger() {
12247       if (fired) return;
12248       fired = true;
12249       fn();
12250     }
12251
12252     // check if document is already loaded
12253     if (document.readyState === 'complete') {
12254       setTimeout(trigger);
12255     } else {
12256       this.on('DOMContentLoaded', trigger); // works for modern browsers and IE9
12257       // we can not use jqLite since we are not done loading and jQuery could be loaded later.
12258       // jshint -W064
12259       JQLite(window).on('load', trigger); // fallback to window.onload for others
12260       // jshint +W064
12261     }
12262   },
12263   toString: function() {
12264     var value = [];
12265     forEach(this, function(e) { value.push('' + e);});
12266     return '[' + value.join(', ') + ']';
12267   },
12268
12269   eq: function(index) {
12270       return (index >= 0) ? jqLite(this[index]) : jqLite(this[this.length + index]);
12271   },
12272
12273   length: 0,
12274   push: push,
12275   sort: [].sort,
12276   splice: [].splice
12277 };
12278
12279 //////////////////////////////////////////
12280 // Functions iterating getter/setters.
12281 // these functions return self on setter and
12282 // value on get.
12283 //////////////////////////////////////////
12284 var BOOLEAN_ATTR = {};
12285 forEach('multiple,selected,checked,disabled,readOnly,required,open'.split(','), function(value) {
12286   BOOLEAN_ATTR[lowercase(value)] = value;
12287 });
12288 var BOOLEAN_ELEMENTS = {};
12289 forEach('input,select,option,textarea,button,form,details'.split(','), function(value) {
12290   BOOLEAN_ELEMENTS[value] = true;
12291 });
12292 var ALIASED_ATTR = {
12293   'ngMinlength': 'minlength',
12294   'ngMaxlength': 'maxlength',
12295   'ngMin': 'min',
12296   'ngMax': 'max',
12297   'ngPattern': 'pattern'
12298 };
12299
12300 function getBooleanAttrName(element, name) {
12301   // check dom last since we will most likely fail on name
12302   var booleanAttr = BOOLEAN_ATTR[name.toLowerCase()];
12303
12304   // booleanAttr is here twice to minimize DOM access
12305   return booleanAttr && BOOLEAN_ELEMENTS[nodeName_(element)] && booleanAttr;
12306 }
12307
12308 function getAliasedAttrName(name) {
12309   return ALIASED_ATTR[name];
12310 }
12311
12312 forEach({
12313   data: jqLiteData,
12314   removeData: jqLiteRemoveData,
12315   hasData: jqLiteHasData
12316 }, function(fn, name) {
12317   JQLite[name] = fn;
12318 });
12319
12320 forEach({
12321   data: jqLiteData,
12322   inheritedData: jqLiteInheritedData,
12323
12324   scope: function(element) {
12325     // Can't use jqLiteData here directly so we stay compatible with jQuery!
12326     return jqLite.data(element, '$scope') || jqLiteInheritedData(element.parentNode || element, ['$isolateScope', '$scope']);
12327   },
12328
12329   isolateScope: function(element) {
12330     // Can't use jqLiteData here directly so we stay compatible with jQuery!
12331     return jqLite.data(element, '$isolateScope') || jqLite.data(element, '$isolateScopeNoTemplate');
12332   },
12333
12334   controller: jqLiteController,
12335
12336   injector: function(element) {
12337     return jqLiteInheritedData(element, '$injector');
12338   },
12339
12340   removeAttr: function(element, name) {
12341     element.removeAttribute(name);
12342   },
12343
12344   hasClass: jqLiteHasClass,
12345
12346   css: function(element, name, value) {
12347     name = camelCase(name);
12348
12349     if (isDefined(value)) {
12350       element.style[name] = value;
12351     } else {
12352       return element.style[name];
12353     }
12354   },
12355
12356   attr: function(element, name, value) {
12357     var nodeType = element.nodeType;
12358     if (nodeType === NODE_TYPE_TEXT || nodeType === NODE_TYPE_ATTRIBUTE || nodeType === NODE_TYPE_COMMENT) {
12359       return;
12360     }
12361     var lowercasedName = lowercase(name);
12362     if (BOOLEAN_ATTR[lowercasedName]) {
12363       if (isDefined(value)) {
12364         if (!!value) {
12365           element[name] = true;
12366           element.setAttribute(name, lowercasedName);
12367         } else {
12368           element[name] = false;
12369           element.removeAttribute(lowercasedName);
12370         }
12371       } else {
12372         return (element[name] ||
12373                  (element.attributes.getNamedItem(name) || noop).specified)
12374                ? lowercasedName
12375                : undefined;
12376       }
12377     } else if (isDefined(value)) {
12378       element.setAttribute(name, value);
12379     } else if (element.getAttribute) {
12380       // the extra argument "2" is to get the right thing for a.href in IE, see jQuery code
12381       // some elements (e.g. Document) don't have get attribute, so return undefined
12382       var ret = element.getAttribute(name, 2);
12383       // normalize non-existing attributes to undefined (as jQuery)
12384       return ret === null ? undefined : ret;
12385     }
12386   },
12387
12388   prop: function(element, name, value) {
12389     if (isDefined(value)) {
12390       element[name] = value;
12391     } else {
12392       return element[name];
12393     }
12394   },
12395
12396   text: (function() {
12397     getText.$dv = '';
12398     return getText;
12399
12400     function getText(element, value) {
12401       if (isUndefined(value)) {
12402         var nodeType = element.nodeType;
12403         return (nodeType === NODE_TYPE_ELEMENT || nodeType === NODE_TYPE_TEXT) ? element.textContent : '';
12404       }
12405       element.textContent = value;
12406     }
12407   })(),
12408
12409   val: function(element, value) {
12410     if (isUndefined(value)) {
12411       if (element.multiple && nodeName_(element) === 'select') {
12412         var result = [];
12413         forEach(element.options, function(option) {
12414           if (option.selected) {
12415             result.push(option.value || option.text);
12416           }
12417         });
12418         return result.length === 0 ? null : result;
12419       }
12420       return element.value;
12421     }
12422     element.value = value;
12423   },
12424
12425   html: function(element, value) {
12426     if (isUndefined(value)) {
12427       return element.innerHTML;
12428     }
12429     jqLiteDealoc(element, true);
12430     element.innerHTML = value;
12431   },
12432
12433   empty: jqLiteEmpty
12434 }, function(fn, name) {
12435   /**
12436    * Properties: writes return selection, reads return first value
12437    */
12438   JQLite.prototype[name] = function(arg1, arg2) {
12439     var i, key;
12440     var nodeCount = this.length;
12441
12442     // jqLiteHasClass has only two arguments, but is a getter-only fn, so we need to special-case it
12443     // in a way that survives minification.
12444     // jqLiteEmpty takes no arguments but is a setter.
12445     if (fn !== jqLiteEmpty &&
12446         (isUndefined((fn.length == 2 && (fn !== jqLiteHasClass && fn !== jqLiteController)) ? arg1 : arg2))) {
12447       if (isObject(arg1)) {
12448
12449         // we are a write, but the object properties are the key/values
12450         for (i = 0; i < nodeCount; i++) {
12451           if (fn === jqLiteData) {
12452             // data() takes the whole object in jQuery
12453             fn(this[i], arg1);
12454           } else {
12455             for (key in arg1) {
12456               fn(this[i], key, arg1[key]);
12457             }
12458           }
12459         }
12460         // return self for chaining
12461         return this;
12462       } else {
12463         // we are a read, so read the first child.
12464         // TODO: do we still need this?
12465         var value = fn.$dv;
12466         // Only if we have $dv do we iterate over all, otherwise it is just the first element.
12467         var jj = (isUndefined(value)) ? Math.min(nodeCount, 1) : nodeCount;
12468         for (var j = 0; j < jj; j++) {
12469           var nodeValue = fn(this[j], arg1, arg2);
12470           value = value ? value + nodeValue : nodeValue;
12471         }
12472         return value;
12473       }
12474     } else {
12475       // we are a write, so apply to all children
12476       for (i = 0; i < nodeCount; i++) {
12477         fn(this[i], arg1, arg2);
12478       }
12479       // return self for chaining
12480       return this;
12481     }
12482   };
12483 });
12484
12485 function createEventHandler(element, events) {
12486   var eventHandler = function(event, type) {
12487     // jQuery specific api
12488     event.isDefaultPrevented = function() {
12489       return event.defaultPrevented;
12490     };
12491
12492     var eventFns = events[type || event.type];
12493     var eventFnsLength = eventFns ? eventFns.length : 0;
12494
12495     if (!eventFnsLength) return;
12496
12497     if (isUndefined(event.immediatePropagationStopped)) {
12498       var originalStopImmediatePropagation = event.stopImmediatePropagation;
12499       event.stopImmediatePropagation = function() {
12500         event.immediatePropagationStopped = true;
12501
12502         if (event.stopPropagation) {
12503           event.stopPropagation();
12504         }
12505
12506         if (originalStopImmediatePropagation) {
12507           originalStopImmediatePropagation.call(event);
12508         }
12509       };
12510     }
12511
12512     event.isImmediatePropagationStopped = function() {
12513       return event.immediatePropagationStopped === true;
12514     };
12515
12516     // Some events have special handlers that wrap the real handler
12517     var handlerWrapper = eventFns.specialHandlerWrapper || defaultHandlerWrapper;
12518
12519     // Copy event handlers in case event handlers array is modified during execution.
12520     if ((eventFnsLength > 1)) {
12521       eventFns = shallowCopy(eventFns);
12522     }
12523
12524     for (var i = 0; i < eventFnsLength; i++) {
12525       if (!event.isImmediatePropagationStopped()) {
12526         handlerWrapper(element, event, eventFns[i]);
12527       }
12528     }
12529   };
12530
12531   // TODO: this is a hack for angularMocks/clearDataCache that makes it possible to deregister all
12532   //       events on `element`
12533   eventHandler.elem = element;
12534   return eventHandler;
12535 }
12536
12537 function defaultHandlerWrapper(element, event, handler) {
12538   handler.call(element, event);
12539 }
12540
12541 function specialMouseHandlerWrapper(target, event, handler) {
12542   // Refer to jQuery's implementation of mouseenter & mouseleave
12543   // Read about mouseenter and mouseleave:
12544   // http://www.quirksmode.org/js/events_mouse.html#link8
12545   var related = event.relatedTarget;
12546   // For mousenter/leave call the handler if related is outside the target.
12547   // NB: No relatedTarget if the mouse left/entered the browser window
12548   if (!related || (related !== target && !jqLiteContains.call(target, related))) {
12549     handler.call(target, event);
12550   }
12551 }
12552
12553 //////////////////////////////////////////
12554 // Functions iterating traversal.
12555 // These functions chain results into a single
12556 // selector.
12557 //////////////////////////////////////////
12558 forEach({
12559   removeData: jqLiteRemoveData,
12560
12561   on: function jqLiteOn(element, type, fn, unsupported) {
12562     if (isDefined(unsupported)) throw jqLiteMinErr('onargs', 'jqLite#on() does not support the `selector` or `eventData` parameters');
12563
12564     // Do not add event handlers to non-elements because they will not be cleaned up.
12565     if (!jqLiteAcceptsData(element)) {
12566       return;
12567     }
12568
12569     var expandoStore = jqLiteExpandoStore(element, true);
12570     var events = expandoStore.events;
12571     var handle = expandoStore.handle;
12572
12573     if (!handle) {
12574       handle = expandoStore.handle = createEventHandler(element, events);
12575     }
12576
12577     // http://jsperf.com/string-indexof-vs-split
12578     var types = type.indexOf(' ') >= 0 ? type.split(' ') : [type];
12579     var i = types.length;
12580
12581     var addHandler = function(type, specialHandlerWrapper, noEventListener) {
12582       var eventFns = events[type];
12583
12584       if (!eventFns) {
12585         eventFns = events[type] = [];
12586         eventFns.specialHandlerWrapper = specialHandlerWrapper;
12587         if (type !== '$destroy' && !noEventListener) {
12588           addEventListenerFn(element, type, handle);
12589         }
12590       }
12591
12592       eventFns.push(fn);
12593     };
12594
12595     while (i--) {
12596       type = types[i];
12597       if (MOUSE_EVENT_MAP[type]) {
12598         addHandler(MOUSE_EVENT_MAP[type], specialMouseHandlerWrapper);
12599         addHandler(type, undefined, true);
12600       } else {
12601         addHandler(type);
12602       }
12603     }
12604   },
12605
12606   off: jqLiteOff,
12607
12608   one: function(element, type, fn) {
12609     element = jqLite(element);
12610
12611     //add the listener twice so that when it is called
12612     //you can remove the original function and still be
12613     //able to call element.off(ev, fn) normally
12614     element.on(type, function onFn() {
12615       element.off(type, fn);
12616       element.off(type, onFn);
12617     });
12618     element.on(type, fn);
12619   },
12620
12621   replaceWith: function(element, replaceNode) {
12622     var index, parent = element.parentNode;
12623     jqLiteDealoc(element);
12624     forEach(new JQLite(replaceNode), function(node) {
12625       if (index) {
12626         parent.insertBefore(node, index.nextSibling);
12627       } else {
12628         parent.replaceChild(node, element);
12629       }
12630       index = node;
12631     });
12632   },
12633
12634   children: function(element) {
12635     var children = [];
12636     forEach(element.childNodes, function(element) {
12637       if (element.nodeType === NODE_TYPE_ELEMENT) {
12638         children.push(element);
12639       }
12640     });
12641     return children;
12642   },
12643
12644   contents: function(element) {
12645     return element.contentDocument || element.childNodes || [];
12646   },
12647
12648   append: function(element, node) {
12649     var nodeType = element.nodeType;
12650     if (nodeType !== NODE_TYPE_ELEMENT && nodeType !== NODE_TYPE_DOCUMENT_FRAGMENT) return;
12651
12652     node = new JQLite(node);
12653
12654     for (var i = 0, ii = node.length; i < ii; i++) {
12655       var child = node[i];
12656       element.appendChild(child);
12657     }
12658   },
12659
12660   prepend: function(element, node) {
12661     if (element.nodeType === NODE_TYPE_ELEMENT) {
12662       var index = element.firstChild;
12663       forEach(new JQLite(node), function(child) {
12664         element.insertBefore(child, index);
12665       });
12666     }
12667   },
12668
12669   wrap: function(element, wrapNode) {
12670     wrapNode = jqLite(wrapNode).eq(0).clone()[0];
12671     var parent = element.parentNode;
12672     if (parent) {
12673       parent.replaceChild(wrapNode, element);
12674     }
12675     wrapNode.appendChild(element);
12676   },
12677
12678   remove: jqLiteRemove,
12679
12680   detach: function(element) {
12681     jqLiteRemove(element, true);
12682   },
12683
12684   after: function(element, newElement) {
12685     var index = element, parent = element.parentNode;
12686     newElement = new JQLite(newElement);
12687
12688     for (var i = 0, ii = newElement.length; i < ii; i++) {
12689       var node = newElement[i];
12690       parent.insertBefore(node, index.nextSibling);
12691       index = node;
12692     }
12693   },
12694
12695   addClass: jqLiteAddClass,
12696   removeClass: jqLiteRemoveClass,
12697
12698   toggleClass: function(element, selector, condition) {
12699     if (selector) {
12700       forEach(selector.split(' '), function(className) {
12701         var classCondition = condition;
12702         if (isUndefined(classCondition)) {
12703           classCondition = !jqLiteHasClass(element, className);
12704         }
12705         (classCondition ? jqLiteAddClass : jqLiteRemoveClass)(element, className);
12706       });
12707     }
12708   },
12709
12710   parent: function(element) {
12711     var parent = element.parentNode;
12712     return parent && parent.nodeType !== NODE_TYPE_DOCUMENT_FRAGMENT ? parent : null;
12713   },
12714
12715   next: function(element) {
12716     return element.nextElementSibling;
12717   },
12718
12719   find: function(element, selector) {
12720     if (element.getElementsByTagName) {
12721       return element.getElementsByTagName(selector);
12722     } else {
12723       return [];
12724     }
12725   },
12726
12727   clone: jqLiteClone,
12728
12729   triggerHandler: function(element, event, extraParameters) {
12730
12731     var dummyEvent, eventFnsCopy, handlerArgs;
12732     var eventName = event.type || event;
12733     var expandoStore = jqLiteExpandoStore(element);
12734     var events = expandoStore && expandoStore.events;
12735     var eventFns = events && events[eventName];
12736
12737     if (eventFns) {
12738       // Create a dummy event to pass to the handlers
12739       dummyEvent = {
12740         preventDefault: function() { this.defaultPrevented = true; },
12741         isDefaultPrevented: function() { return this.defaultPrevented === true; },
12742         stopImmediatePropagation: function() { this.immediatePropagationStopped = true; },
12743         isImmediatePropagationStopped: function() { return this.immediatePropagationStopped === true; },
12744         stopPropagation: noop,
12745         type: eventName,
12746         target: element
12747       };
12748
12749       // If a custom event was provided then extend our dummy event with it
12750       if (event.type) {
12751         dummyEvent = extend(dummyEvent, event);
12752       }
12753
12754       // Copy event handlers in case event handlers array is modified during execution.
12755       eventFnsCopy = shallowCopy(eventFns);
12756       handlerArgs = extraParameters ? [dummyEvent].concat(extraParameters) : [dummyEvent];
12757
12758       forEach(eventFnsCopy, function(fn) {
12759         if (!dummyEvent.isImmediatePropagationStopped()) {
12760           fn.apply(element, handlerArgs);
12761         }
12762       });
12763     }
12764   }
12765 }, function(fn, name) {
12766   /**
12767    * chaining functions
12768    */
12769   JQLite.prototype[name] = function(arg1, arg2, arg3) {
12770     var value;
12771
12772     for (var i = 0, ii = this.length; i < ii; i++) {
12773       if (isUndefined(value)) {
12774         value = fn(this[i], arg1, arg2, arg3);
12775         if (isDefined(value)) {
12776           // any function which returns a value needs to be wrapped
12777           value = jqLite(value);
12778         }
12779       } else {
12780         jqLiteAddNodes(value, fn(this[i], arg1, arg2, arg3));
12781       }
12782     }
12783     return isDefined(value) ? value : this;
12784   };
12785
12786   // bind legacy bind/unbind to on/off
12787   JQLite.prototype.bind = JQLite.prototype.on;
12788   JQLite.prototype.unbind = JQLite.prototype.off;
12789 });
12790
12791
12792 // Provider for private $$jqLite service
12793 function $$jqLiteProvider() {
12794   this.$get = function $$jqLite() {
12795     return extend(JQLite, {
12796       hasClass: function(node, classes) {
12797         if (node.attr) node = node[0];
12798         return jqLiteHasClass(node, classes);
12799       },
12800       addClass: function(node, classes) {
12801         if (node.attr) node = node[0];
12802         return jqLiteAddClass(node, classes);
12803       },
12804       removeClass: function(node, classes) {
12805         if (node.attr) node = node[0];
12806         return jqLiteRemoveClass(node, classes);
12807       }
12808     });
12809   };
12810 }
12811
12812 /**
12813  * Computes a hash of an 'obj'.
12814  * Hash of a:
12815  *  string is string
12816  *  number is number as string
12817  *  object is either result of calling $$hashKey function on the object or uniquely generated id,
12818  *         that is also assigned to the $$hashKey property of the object.
12819  *
12820  * @param obj
12821  * @returns {string} hash string such that the same input will have the same hash string.
12822  *         The resulting string key is in 'type:hashKey' format.
12823  */
12824 function hashKey(obj, nextUidFn) {
12825   var key = obj && obj.$$hashKey;
12826
12827   if (key) {
12828     if (typeof key === 'function') {
12829       key = obj.$$hashKey();
12830     }
12831     return key;
12832   }
12833
12834   var objType = typeof obj;
12835   if (objType == 'function' || (objType == 'object' && obj !== null)) {
12836     key = obj.$$hashKey = objType + ':' + (nextUidFn || nextUid)();
12837   } else {
12838     key = objType + ':' + obj;
12839   }
12840
12841   return key;
12842 }
12843
12844 /**
12845  * HashMap which can use objects as keys
12846  */
12847 function HashMap(array, isolatedUid) {
12848   if (isolatedUid) {
12849     var uid = 0;
12850     this.nextUid = function() {
12851       return ++uid;
12852     };
12853   }
12854   forEach(array, this.put, this);
12855 }
12856 HashMap.prototype = {
12857   /**
12858    * Store key value pair
12859    * @param key key to store can be any type
12860    * @param value value to store can be any type
12861    */
12862   put: function(key, value) {
12863     this[hashKey(key, this.nextUid)] = value;
12864   },
12865
12866   /**
12867    * @param key
12868    * @returns {Object} the value for the key
12869    */
12870   get: function(key) {
12871     return this[hashKey(key, this.nextUid)];
12872   },
12873
12874   /**
12875    * Remove the key/value pair
12876    * @param key
12877    */
12878   remove: function(key) {
12879     var value = this[key = hashKey(key, this.nextUid)];
12880     delete this[key];
12881     return value;
12882   }
12883 };
12884
12885 var $$HashMapProvider = [function() {
12886   this.$get = [function() {
12887     return HashMap;
12888   }];
12889 }];
12890
12891 /**
12892  * @ngdoc function
12893  * @module ng
12894  * @name angular.injector
12895  * @kind function
12896  *
12897  * @description
12898  * Creates an injector object that can be used for retrieving services as well as for
12899  * dependency injection (see {@link guide/di dependency injection}).
12900  *
12901  * @param {Array.<string|Function>} modules A list of module functions or their aliases. See
12902  *     {@link angular.module}. The `ng` module must be explicitly added.
12903  * @param {boolean=} [strictDi=false] Whether the injector should be in strict mode, which
12904  *     disallows argument name annotation inference.
12905  * @returns {injector} Injector object. See {@link auto.$injector $injector}.
12906  *
12907  * @example
12908  * Typical usage
12909  * ```js
12910  *   // create an injector
12911  *   var $injector = angular.injector(['ng']);
12912  *
12913  *   // use the injector to kick off your application
12914  *   // use the type inference to auto inject arguments, or use implicit injection
12915  *   $injector.invoke(function($rootScope, $compile, $document) {
12916  *     $compile($document)($rootScope);
12917  *     $rootScope.$digest();
12918  *   });
12919  * ```
12920  *
12921  * Sometimes you want to get access to the injector of a currently running Angular app
12922  * from outside Angular. Perhaps, you want to inject and compile some markup after the
12923  * application has been bootstrapped. You can do this using the extra `injector()` added
12924  * to JQuery/jqLite elements. See {@link angular.element}.
12925  *
12926  * *This is fairly rare but could be the case if a third party library is injecting the
12927  * markup.*
12928  *
12929  * In the following example a new block of HTML containing a `ng-controller`
12930  * directive is added to the end of the document body by JQuery. We then compile and link
12931  * it into the current AngularJS scope.
12932  *
12933  * ```js
12934  * var $div = $('<div ng-controller="MyCtrl">{{content.label}}</div>');
12935  * $(document.body).append($div);
12936  *
12937  * angular.element(document).injector().invoke(function($compile) {
12938  *   var scope = angular.element($div).scope();
12939  *   $compile($div)(scope);
12940  * });
12941  * ```
12942  */
12943
12944
12945 /**
12946  * @ngdoc module
12947  * @name auto
12948  * @description
12949  *
12950  * Implicit module which gets automatically added to each {@link auto.$injector $injector}.
12951  */
12952
12953 var FN_ARGS = /^[^\(]*\(\s*([^\)]*)\)/m;
12954 var FN_ARG_SPLIT = /,/;
12955 var FN_ARG = /^\s*(_?)(\S+?)\1\s*$/;
12956 var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;
12957 var $injectorMinErr = minErr('$injector');
12958
12959 function anonFn(fn) {
12960   // For anonymous functions, showing at the very least the function signature can help in
12961   // debugging.
12962   var fnText = fn.toString().replace(STRIP_COMMENTS, ''),
12963       args = fnText.match(FN_ARGS);
12964   if (args) {
12965     return 'function(' + (args[1] || '').replace(/[\s\r\n]+/, ' ') + ')';
12966   }
12967   return 'fn';
12968 }
12969
12970 function annotate(fn, strictDi, name) {
12971   var $inject,
12972       fnText,
12973       argDecl,
12974       last;
12975
12976   if (typeof fn === 'function') {
12977     if (!($inject = fn.$inject)) {
12978       $inject = [];
12979       if (fn.length) {
12980         if (strictDi) {
12981           if (!isString(name) || !name) {
12982             name = fn.name || anonFn(fn);
12983           }
12984           throw $injectorMinErr('strictdi',
12985             '{0} is not using explicit annotation and cannot be invoked in strict mode', name);
12986         }
12987         fnText = fn.toString().replace(STRIP_COMMENTS, '');
12988         argDecl = fnText.match(FN_ARGS);
12989         forEach(argDecl[1].split(FN_ARG_SPLIT), function(arg) {
12990           arg.replace(FN_ARG, function(all, underscore, name) {
12991             $inject.push(name);
12992           });
12993         });
12994       }
12995       fn.$inject = $inject;
12996     }
12997   } else if (isArray(fn)) {
12998     last = fn.length - 1;
12999     assertArgFn(fn[last], 'fn');
13000     $inject = fn.slice(0, last);
13001   } else {
13002     assertArgFn(fn, 'fn', true);
13003   }
13004   return $inject;
13005 }
13006
13007 ///////////////////////////////////////
13008
13009 /**
13010  * @ngdoc service
13011  * @name $injector
13012  *
13013  * @description
13014  *
13015  * `$injector` is used to retrieve object instances as defined by
13016  * {@link auto.$provide provider}, instantiate types, invoke methods,
13017  * and load modules.
13018  *
13019  * The following always holds true:
13020  *
13021  * ```js
13022  *   var $injector = angular.injector();
13023  *   expect($injector.get('$injector')).toBe($injector);
13024  *   expect($injector.invoke(function($injector) {
13025  *     return $injector;
13026  *   })).toBe($injector);
13027  * ```
13028  *
13029  * # Injection Function Annotation
13030  *
13031  * JavaScript does not have annotations, and annotations are needed for dependency injection. The
13032  * following are all valid ways of annotating function with injection arguments and are equivalent.
13033  *
13034  * ```js
13035  *   // inferred (only works if code not minified/obfuscated)
13036  *   $injector.invoke(function(serviceA){});
13037  *
13038  *   // annotated
13039  *   function explicit(serviceA) {};
13040  *   explicit.$inject = ['serviceA'];
13041  *   $injector.invoke(explicit);
13042  *
13043  *   // inline
13044  *   $injector.invoke(['serviceA', function(serviceA){}]);
13045  * ```
13046  *
13047  * ## Inference
13048  *
13049  * In JavaScript calling `toString()` on a function returns the function definition. The definition
13050  * can then be parsed and the function arguments can be extracted. This method of discovering
13051  * annotations is disallowed when the injector is in strict mode.
13052  * *NOTE:* This does not work with minification, and obfuscation tools since these tools change the
13053  * argument names.
13054  *
13055  * ## `$inject` Annotation
13056  * By adding an `$inject` property onto a function the injection parameters can be specified.
13057  *
13058  * ## Inline
13059  * As an array of injection names, where the last item in the array is the function to call.
13060  */
13061
13062 /**
13063  * @ngdoc method
13064  * @name $injector#get
13065  *
13066  * @description
13067  * Return an instance of the service.
13068  *
13069  * @param {string} name The name of the instance to retrieve.
13070  * @param {string=} caller An optional string to provide the origin of the function call for error messages.
13071  * @return {*} The instance.
13072  */
13073
13074 /**
13075  * @ngdoc method
13076  * @name $injector#invoke
13077  *
13078  * @description
13079  * Invoke the method and supply the method arguments from the `$injector`.
13080  *
13081  * @param {Function|Array.<string|Function>} fn The injectable function to invoke. Function parameters are
13082  *   injected according to the {@link guide/di $inject Annotation} rules.
13083  * @param {Object=} self The `this` for the invoked method.
13084  * @param {Object=} locals Optional object. If preset then any argument names are read from this
13085  *                         object first, before the `$injector` is consulted.
13086  * @returns {*} the value returned by the invoked `fn` function.
13087  */
13088
13089 /**
13090  * @ngdoc method
13091  * @name $injector#has
13092  *
13093  * @description
13094  * Allows the user to query if the particular service exists.
13095  *
13096  * @param {string} name Name of the service to query.
13097  * @returns {boolean} `true` if injector has given service.
13098  */
13099
13100 /**
13101  * @ngdoc method
13102  * @name $injector#instantiate
13103  * @description
13104  * Create a new instance of JS type. The method takes a constructor function, invokes the new
13105  * operator, and supplies all of the arguments to the constructor function as specified by the
13106  * constructor annotation.
13107  *
13108  * @param {Function} Type Annotated constructor function.
13109  * @param {Object=} locals Optional object. If preset then any argument names are read from this
13110  * object first, before the `$injector` is consulted.
13111  * @returns {Object} new instance of `Type`.
13112  */
13113
13114 /**
13115  * @ngdoc method
13116  * @name $injector#annotate
13117  *
13118  * @description
13119  * Returns an array of service names which the function is requesting for injection. This API is
13120  * used by the injector to determine which services need to be injected into the function when the
13121  * function is invoked. There are three ways in which the function can be annotated with the needed
13122  * dependencies.
13123  *
13124  * # Argument names
13125  *
13126  * The simplest form is to extract the dependencies from the arguments of the function. This is done
13127  * by converting the function into a string using `toString()` method and extracting the argument
13128  * names.
13129  * ```js
13130  *   // Given
13131  *   function MyController($scope, $route) {
13132  *     // ...
13133  *   }
13134  *
13135  *   // Then
13136  *   expect(injector.annotate(MyController)).toEqual(['$scope', '$route']);
13137  * ```
13138  *
13139  * You can disallow this method by using strict injection mode.
13140  *
13141  * This method does not work with code minification / obfuscation. For this reason the following
13142  * annotation strategies are supported.
13143  *
13144  * # The `$inject` property
13145  *
13146  * If a function has an `$inject` property and its value is an array of strings, then the strings
13147  * represent names of services to be injected into the function.
13148  * ```js
13149  *   // Given
13150  *   var MyController = function(obfuscatedScope, obfuscatedRoute) {
13151  *     // ...
13152  *   }
13153  *   // Define function dependencies
13154  *   MyController['$inject'] = ['$scope', '$route'];
13155  *
13156  *   // Then
13157  *   expect(injector.annotate(MyController)).toEqual(['$scope', '$route']);
13158  * ```
13159  *
13160  * # The array notation
13161  *
13162  * It is often desirable to inline Injected functions and that's when setting the `$inject` property
13163  * is very inconvenient. In these situations using the array notation to specify the dependencies in
13164  * a way that survives minification is a better choice:
13165  *
13166  * ```js
13167  *   // We wish to write this (not minification / obfuscation safe)
13168  *   injector.invoke(function($compile, $rootScope) {
13169  *     // ...
13170  *   });
13171  *
13172  *   // We are forced to write break inlining
13173  *   var tmpFn = function(obfuscatedCompile, obfuscatedRootScope) {
13174  *     // ...
13175  *   };
13176  *   tmpFn.$inject = ['$compile', '$rootScope'];
13177  *   injector.invoke(tmpFn);
13178  *
13179  *   // To better support inline function the inline annotation is supported
13180  *   injector.invoke(['$compile', '$rootScope', function(obfCompile, obfRootScope) {
13181  *     // ...
13182  *   }]);
13183  *
13184  *   // Therefore
13185  *   expect(injector.annotate(
13186  *      ['$compile', '$rootScope', function(obfus_$compile, obfus_$rootScope) {}])
13187  *    ).toEqual(['$compile', '$rootScope']);
13188  * ```
13189  *
13190  * @param {Function|Array.<string|Function>} fn Function for which dependent service names need to
13191  * be retrieved as described above.
13192  *
13193  * @param {boolean=} [strictDi=false] Disallow argument name annotation inference.
13194  *
13195  * @returns {Array.<string>} The names of the services which the function requires.
13196  */
13197
13198
13199
13200
13201 /**
13202  * @ngdoc service
13203  * @name $provide
13204  *
13205  * @description
13206  *
13207  * The {@link auto.$provide $provide} service has a number of methods for registering components
13208  * with the {@link auto.$injector $injector}. Many of these functions are also exposed on
13209  * {@link angular.Module}.
13210  *
13211  * An Angular **service** is a singleton object created by a **service factory**.  These **service
13212  * factories** are functions which, in turn, are created by a **service provider**.
13213  * The **service providers** are constructor functions. When instantiated they must contain a
13214  * property called `$get`, which holds the **service factory** function.
13215  *
13216  * When you request a service, the {@link auto.$injector $injector} is responsible for finding the
13217  * correct **service provider**, instantiating it and then calling its `$get` **service factory**
13218  * function to get the instance of the **service**.
13219  *
13220  * Often services have no configuration options and there is no need to add methods to the service
13221  * provider.  The provider will be no more than a constructor function with a `$get` property. For
13222  * these cases the {@link auto.$provide $provide} service has additional helper methods to register
13223  * services without specifying a provider.
13224  *
13225  * * {@link auto.$provide#provider provider(provider)} - registers a **service provider** with the
13226  *     {@link auto.$injector $injector}
13227  * * {@link auto.$provide#constant constant(obj)} - registers a value/object that can be accessed by
13228  *     providers and services.
13229  * * {@link auto.$provide#value value(obj)} - registers a value/object that can only be accessed by
13230  *     services, not providers.
13231  * * {@link auto.$provide#factory factory(fn)} - registers a service **factory function**, `fn`,
13232  *     that will be wrapped in a **service provider** object, whose `$get` property will contain the
13233  *     given factory function.
13234  * * {@link auto.$provide#service service(class)} - registers a **constructor function**, `class`
13235  *     that will be wrapped in a **service provider** object, whose `$get` property will instantiate
13236  *      a new object using the given constructor function.
13237  *
13238  * See the individual methods for more information and examples.
13239  */
13240
13241 /**
13242  * @ngdoc method
13243  * @name $provide#provider
13244  * @description
13245  *
13246  * Register a **provider function** with the {@link auto.$injector $injector}. Provider functions
13247  * are constructor functions, whose instances are responsible for "providing" a factory for a
13248  * service.
13249  *
13250  * Service provider names start with the name of the service they provide followed by `Provider`.
13251  * For example, the {@link ng.$log $log} service has a provider called
13252  * {@link ng.$logProvider $logProvider}.
13253  *
13254  * Service provider objects can have additional methods which allow configuration of the provider
13255  * and its service. Importantly, you can configure what kind of service is created by the `$get`
13256  * method, or how that service will act. For example, the {@link ng.$logProvider $logProvider} has a
13257  * method {@link ng.$logProvider#debugEnabled debugEnabled}
13258  * which lets you specify whether the {@link ng.$log $log} service will log debug messages to the
13259  * console or not.
13260  *
13261  * @param {string} name The name of the instance. NOTE: the provider will be available under `name +
13262                         'Provider'` key.
13263  * @param {(Object|function())} provider If the provider is:
13264  *
13265  *   - `Object`: then it should have a `$get` method. The `$get` method will be invoked using
13266  *     {@link auto.$injector#invoke $injector.invoke()} when an instance needs to be created.
13267  *   - `Constructor`: a new instance of the provider will be created using
13268  *     {@link auto.$injector#instantiate $injector.instantiate()}, then treated as `object`.
13269  *
13270  * @returns {Object} registered provider instance
13271
13272  * @example
13273  *
13274  * The following example shows how to create a simple event tracking service and register it using
13275  * {@link auto.$provide#provider $provide.provider()}.
13276  *
13277  * ```js
13278  *  // Define the eventTracker provider
13279  *  function EventTrackerProvider() {
13280  *    var trackingUrl = '/track';
13281  *
13282  *    // A provider method for configuring where the tracked events should been saved
13283  *    this.setTrackingUrl = function(url) {
13284  *      trackingUrl = url;
13285  *    };
13286  *
13287  *    // The service factory function
13288  *    this.$get = ['$http', function($http) {
13289  *      var trackedEvents = {};
13290  *      return {
13291  *        // Call this to track an event
13292  *        event: function(event) {
13293  *          var count = trackedEvents[event] || 0;
13294  *          count += 1;
13295  *          trackedEvents[event] = count;
13296  *          return count;
13297  *        },
13298  *        // Call this to save the tracked events to the trackingUrl
13299  *        save: function() {
13300  *          $http.post(trackingUrl, trackedEvents);
13301  *        }
13302  *      };
13303  *    }];
13304  *  }
13305  *
13306  *  describe('eventTracker', function() {
13307  *    var postSpy;
13308  *
13309  *    beforeEach(module(function($provide) {
13310  *      // Register the eventTracker provider
13311  *      $provide.provider('eventTracker', EventTrackerProvider);
13312  *    }));
13313  *
13314  *    beforeEach(module(function(eventTrackerProvider) {
13315  *      // Configure eventTracker provider
13316  *      eventTrackerProvider.setTrackingUrl('/custom-track');
13317  *    }));
13318  *
13319  *    it('tracks events', inject(function(eventTracker) {
13320  *      expect(eventTracker.event('login')).toEqual(1);
13321  *      expect(eventTracker.event('login')).toEqual(2);
13322  *    }));
13323  *
13324  *    it('saves to the tracking url', inject(function(eventTracker, $http) {
13325  *      postSpy = spyOn($http, 'post');
13326  *      eventTracker.event('login');
13327  *      eventTracker.save();
13328  *      expect(postSpy).toHaveBeenCalled();
13329  *      expect(postSpy.mostRecentCall.args[0]).not.toEqual('/track');
13330  *      expect(postSpy.mostRecentCall.args[0]).toEqual('/custom-track');
13331  *      expect(postSpy.mostRecentCall.args[1]).toEqual({ 'login': 1 });
13332  *    }));
13333  *  });
13334  * ```
13335  */
13336
13337 /**
13338  * @ngdoc method
13339  * @name $provide#factory
13340  * @description
13341  *
13342  * Register a **service factory**, which will be called to return the service instance.
13343  * This is short for registering a service where its provider consists of only a `$get` property,
13344  * which is the given service factory function.
13345  * You should use {@link auto.$provide#factory $provide.factory(getFn)} if you do not need to
13346  * configure your service in a provider.
13347  *
13348  * @param {string} name The name of the instance.
13349  * @param {Function|Array.<string|Function>} $getFn The injectable $getFn for the instance creation.
13350  *                      Internally this is a short hand for `$provide.provider(name, {$get: $getFn})`.
13351  * @returns {Object} registered provider instance
13352  *
13353  * @example
13354  * Here is an example of registering a service
13355  * ```js
13356  *   $provide.factory('ping', ['$http', function($http) {
13357  *     return function ping() {
13358  *       return $http.send('/ping');
13359  *     };
13360  *   }]);
13361  * ```
13362  * You would then inject and use this service like this:
13363  * ```js
13364  *   someModule.controller('Ctrl', ['ping', function(ping) {
13365  *     ping();
13366  *   }]);
13367  * ```
13368  */
13369
13370
13371 /**
13372  * @ngdoc method
13373  * @name $provide#service
13374  * @description
13375  *
13376  * Register a **service constructor**, which will be invoked with `new` to create the service
13377  * instance.
13378  * This is short for registering a service where its provider's `$get` property is the service
13379  * constructor function that will be used to instantiate the service instance.
13380  *
13381  * You should use {@link auto.$provide#service $provide.service(class)} if you define your service
13382  * as a type/class.
13383  *
13384  * @param {string} name The name of the instance.
13385  * @param {Function|Array.<string|Function>} constructor An injectable class (constructor function)
13386  *     that will be instantiated.
13387  * @returns {Object} registered provider instance
13388  *
13389  * @example
13390  * Here is an example of registering a service using
13391  * {@link auto.$provide#service $provide.service(class)}.
13392  * ```js
13393  *   var Ping = function($http) {
13394  *     this.$http = $http;
13395  *   };
13396  *
13397  *   Ping.$inject = ['$http'];
13398  *
13399  *   Ping.prototype.send = function() {
13400  *     return this.$http.get('/ping');
13401  *   };
13402  *   $provide.service('ping', Ping);
13403  * ```
13404  * You would then inject and use this service like this:
13405  * ```js
13406  *   someModule.controller('Ctrl', ['ping', function(ping) {
13407  *     ping.send();
13408  *   }]);
13409  * ```
13410  */
13411
13412
13413 /**
13414  * @ngdoc method
13415  * @name $provide#value
13416  * @description
13417  *
13418  * Register a **value service** with the {@link auto.$injector $injector}, such as a string, a
13419  * number, an array, an object or a function.  This is short for registering a service where its
13420  * provider's `$get` property is a factory function that takes no arguments and returns the **value
13421  * service**.
13422  *
13423  * Value services are similar to constant services, except that they cannot be injected into a
13424  * module configuration function (see {@link angular.Module#config}) but they can be overridden by
13425  * an Angular
13426  * {@link auto.$provide#decorator decorator}.
13427  *
13428  * @param {string} name The name of the instance.
13429  * @param {*} value The value.
13430  * @returns {Object} registered provider instance
13431  *
13432  * @example
13433  * Here are some examples of creating value services.
13434  * ```js
13435  *   $provide.value('ADMIN_USER', 'admin');
13436  *
13437  *   $provide.value('RoleLookup', { admin: 0, writer: 1, reader: 2 });
13438  *
13439  *   $provide.value('halfOf', function(value) {
13440  *     return value / 2;
13441  *   });
13442  * ```
13443  */
13444
13445
13446 /**
13447  * @ngdoc method
13448  * @name $provide#constant
13449  * @description
13450  *
13451  * Register a **constant service**, such as a string, a number, an array, an object or a function,
13452  * with the {@link auto.$injector $injector}. Unlike {@link auto.$provide#value value} it can be
13453  * injected into a module configuration function (see {@link angular.Module#config}) and it cannot
13454  * be overridden by an Angular {@link auto.$provide#decorator decorator}.
13455  *
13456  * @param {string} name The name of the constant.
13457  * @param {*} value The constant value.
13458  * @returns {Object} registered instance
13459  *
13460  * @example
13461  * Here a some examples of creating constants:
13462  * ```js
13463  *   $provide.constant('SHARD_HEIGHT', 306);
13464  *
13465  *   $provide.constant('MY_COLOURS', ['red', 'blue', 'grey']);
13466  *
13467  *   $provide.constant('double', function(value) {
13468  *     return value * 2;
13469  *   });
13470  * ```
13471  */
13472
13473
13474 /**
13475  * @ngdoc method
13476  * @name $provide#decorator
13477  * @description
13478  *
13479  * Register a **service decorator** with the {@link auto.$injector $injector}. A service decorator
13480  * intercepts the creation of a service, allowing it to override or modify the behaviour of the
13481  * service. The object returned by the decorator may be the original service, or a new service
13482  * object which replaces or wraps and delegates to the original service.
13483  *
13484  * @param {string} name The name of the service to decorate.
13485  * @param {Function|Array.<string|Function>} decorator This function will be invoked when the service needs to be
13486  *    instantiated and should return the decorated service instance. The function is called using
13487  *    the {@link auto.$injector#invoke injector.invoke} method and is therefore fully injectable.
13488  *    Local injection arguments:
13489  *
13490  *    * `$delegate` - The original service instance, which can be monkey patched, configured,
13491  *      decorated or delegated to.
13492  *
13493  * @example
13494  * Here we decorate the {@link ng.$log $log} service to convert warnings to errors by intercepting
13495  * calls to {@link ng.$log#error $log.warn()}.
13496  * ```js
13497  *   $provide.decorator('$log', ['$delegate', function($delegate) {
13498  *     $delegate.warn = $delegate.error;
13499  *     return $delegate;
13500  *   }]);
13501  * ```
13502  */
13503
13504
13505 function createInjector(modulesToLoad, strictDi) {
13506   strictDi = (strictDi === true);
13507   var INSTANTIATING = {},
13508       providerSuffix = 'Provider',
13509       path = [],
13510       loadedModules = new HashMap([], true),
13511       providerCache = {
13512         $provide: {
13513             provider: supportObject(provider),
13514             factory: supportObject(factory),
13515             service: supportObject(service),
13516             value: supportObject(value),
13517             constant: supportObject(constant),
13518             decorator: decorator
13519           }
13520       },
13521       providerInjector = (providerCache.$injector =
13522           createInternalInjector(providerCache, function(serviceName, caller) {
13523             if (angular.isString(caller)) {
13524               path.push(caller);
13525             }
13526             throw $injectorMinErr('unpr', "Unknown provider: {0}", path.join(' <- '));
13527           })),
13528       instanceCache = {},
13529       instanceInjector = (instanceCache.$injector =
13530           createInternalInjector(instanceCache, function(serviceName, caller) {
13531             var provider = providerInjector.get(serviceName + providerSuffix, caller);
13532             return instanceInjector.invoke(provider.$get, provider, undefined, serviceName);
13533           }));
13534
13535
13536   forEach(loadModules(modulesToLoad), function(fn) { if (fn) instanceInjector.invoke(fn); });
13537
13538   return instanceInjector;
13539
13540   ////////////////////////////////////
13541   // $provider
13542   ////////////////////////////////////
13543
13544   function supportObject(delegate) {
13545     return function(key, value) {
13546       if (isObject(key)) {
13547         forEach(key, reverseParams(delegate));
13548       } else {
13549         return delegate(key, value);
13550       }
13551     };
13552   }
13553
13554   function provider(name, provider_) {
13555     assertNotHasOwnProperty(name, 'service');
13556     if (isFunction(provider_) || isArray(provider_)) {
13557       provider_ = providerInjector.instantiate(provider_);
13558     }
13559     if (!provider_.$get) {
13560       throw $injectorMinErr('pget', "Provider '{0}' must define $get factory method.", name);
13561     }
13562     return providerCache[name + providerSuffix] = provider_;
13563   }
13564
13565   function enforceReturnValue(name, factory) {
13566     return function enforcedReturnValue() {
13567       var result = instanceInjector.invoke(factory, this);
13568       if (isUndefined(result)) {
13569         throw $injectorMinErr('undef', "Provider '{0}' must return a value from $get factory method.", name);
13570       }
13571       return result;
13572     };
13573   }
13574
13575   function factory(name, factoryFn, enforce) {
13576     return provider(name, {
13577       $get: enforce !== false ? enforceReturnValue(name, factoryFn) : factoryFn
13578     });
13579   }
13580
13581   function service(name, constructor) {
13582     return factory(name, ['$injector', function($injector) {
13583       return $injector.instantiate(constructor);
13584     }]);
13585   }
13586
13587   function value(name, val) { return factory(name, valueFn(val), false); }
13588
13589   function constant(name, value) {
13590     assertNotHasOwnProperty(name, 'constant');
13591     providerCache[name] = value;
13592     instanceCache[name] = value;
13593   }
13594
13595   function decorator(serviceName, decorFn) {
13596     var origProvider = providerInjector.get(serviceName + providerSuffix),
13597         orig$get = origProvider.$get;
13598
13599     origProvider.$get = function() {
13600       var origInstance = instanceInjector.invoke(orig$get, origProvider);
13601       return instanceInjector.invoke(decorFn, null, {$delegate: origInstance});
13602     };
13603   }
13604
13605   ////////////////////////////////////
13606   // Module Loading
13607   ////////////////////////////////////
13608   function loadModules(modulesToLoad) {
13609     assertArg(isUndefined(modulesToLoad) || isArray(modulesToLoad), 'modulesToLoad', 'not an array');
13610     var runBlocks = [], moduleFn;
13611     forEach(modulesToLoad, function(module) {
13612       if (loadedModules.get(module)) return;
13613       loadedModules.put(module, true);
13614
13615       function runInvokeQueue(queue) {
13616         var i, ii;
13617         for (i = 0, ii = queue.length; i < ii; i++) {
13618           var invokeArgs = queue[i],
13619               provider = providerInjector.get(invokeArgs[0]);
13620
13621           provider[invokeArgs[1]].apply(provider, invokeArgs[2]);
13622         }
13623       }
13624
13625       try {
13626         if (isString(module)) {
13627           moduleFn = angularModule(module);
13628           runBlocks = runBlocks.concat(loadModules(moduleFn.requires)).concat(moduleFn._runBlocks);
13629           runInvokeQueue(moduleFn._invokeQueue);
13630           runInvokeQueue(moduleFn._configBlocks);
13631         } else if (isFunction(module)) {
13632             runBlocks.push(providerInjector.invoke(module));
13633         } else if (isArray(module)) {
13634             runBlocks.push(providerInjector.invoke(module));
13635         } else {
13636           assertArgFn(module, 'module');
13637         }
13638       } catch (e) {
13639         if (isArray(module)) {
13640           module = module[module.length - 1];
13641         }
13642         if (e.message && e.stack && e.stack.indexOf(e.message) == -1) {
13643           // Safari & FF's stack traces don't contain error.message content
13644           // unlike those of Chrome and IE
13645           // So if stack doesn't contain message, we create a new string that contains both.
13646           // Since error.stack is read-only in Safari, I'm overriding e and not e.stack here.
13647           /* jshint -W022 */
13648           e = e.message + '\n' + e.stack;
13649         }
13650         throw $injectorMinErr('modulerr', "Failed to instantiate module {0} due to:\n{1}",
13651                   module, e.stack || e.message || e);
13652       }
13653     });
13654     return runBlocks;
13655   }
13656
13657   ////////////////////////////////////
13658   // internal Injector
13659   ////////////////////////////////////
13660
13661   function createInternalInjector(cache, factory) {
13662
13663     function getService(serviceName, caller) {
13664       if (cache.hasOwnProperty(serviceName)) {
13665         if (cache[serviceName] === INSTANTIATING) {
13666           throw $injectorMinErr('cdep', 'Circular dependency found: {0}',
13667                     serviceName + ' <- ' + path.join(' <- '));
13668         }
13669         return cache[serviceName];
13670       } else {
13671         try {
13672           path.unshift(serviceName);
13673           cache[serviceName] = INSTANTIATING;
13674           return cache[serviceName] = factory(serviceName, caller);
13675         } catch (err) {
13676           if (cache[serviceName] === INSTANTIATING) {
13677             delete cache[serviceName];
13678           }
13679           throw err;
13680         } finally {
13681           path.shift();
13682         }
13683       }
13684     }
13685
13686     function invoke(fn, self, locals, serviceName) {
13687       if (typeof locals === 'string') {
13688         serviceName = locals;
13689         locals = null;
13690       }
13691
13692       var args = [],
13693           $inject = createInjector.$$annotate(fn, strictDi, serviceName),
13694           length, i,
13695           key;
13696
13697       for (i = 0, length = $inject.length; i < length; i++) {
13698         key = $inject[i];
13699         if (typeof key !== 'string') {
13700           throw $injectorMinErr('itkn',
13701                   'Incorrect injection token! Expected service name as string, got {0}', key);
13702         }
13703         args.push(
13704           locals && locals.hasOwnProperty(key)
13705           ? locals[key]
13706           : getService(key, serviceName)
13707         );
13708       }
13709       if (isArray(fn)) {
13710         fn = fn[length];
13711       }
13712
13713       // http://jsperf.com/angularjs-invoke-apply-vs-switch
13714       // #5388
13715       return fn.apply(self, args);
13716     }
13717
13718     function instantiate(Type, locals, serviceName) {
13719       // Check if Type is annotated and use just the given function at n-1 as parameter
13720       // e.g. someModule.factory('greeter', ['$window', function(renamed$window) {}]);
13721       // Object creation: http://jsperf.com/create-constructor/2
13722       var instance = Object.create((isArray(Type) ? Type[Type.length - 1] : Type).prototype || null);
13723       var returnedValue = invoke(Type, instance, locals, serviceName);
13724
13725       return isObject(returnedValue) || isFunction(returnedValue) ? returnedValue : instance;
13726     }
13727
13728     return {
13729       invoke: invoke,
13730       instantiate: instantiate,
13731       get: getService,
13732       annotate: createInjector.$$annotate,
13733       has: function(name) {
13734         return providerCache.hasOwnProperty(name + providerSuffix) || cache.hasOwnProperty(name);
13735       }
13736     };
13737   }
13738 }
13739
13740 createInjector.$$annotate = annotate;
13741
13742 /**
13743  * @ngdoc provider
13744  * @name $anchorScrollProvider
13745  *
13746  * @description
13747  * Use `$anchorScrollProvider` to disable automatic scrolling whenever
13748  * {@link ng.$location#hash $location.hash()} changes.
13749  */
13750 function $AnchorScrollProvider() {
13751
13752   var autoScrollingEnabled = true;
13753
13754   /**
13755    * @ngdoc method
13756    * @name $anchorScrollProvider#disableAutoScrolling
13757    *
13758    * @description
13759    * By default, {@link ng.$anchorScroll $anchorScroll()} will automatically detect changes to
13760    * {@link ng.$location#hash $location.hash()} and scroll to the element matching the new hash.<br />
13761    * Use this method to disable automatic scrolling.
13762    *
13763    * If automatic scrolling is disabled, one must explicitly call
13764    * {@link ng.$anchorScroll $anchorScroll()} in order to scroll to the element related to the
13765    * current hash.
13766    */
13767   this.disableAutoScrolling = function() {
13768     autoScrollingEnabled = false;
13769   };
13770
13771   /**
13772    * @ngdoc service
13773    * @name $anchorScroll
13774    * @kind function
13775    * @requires $window
13776    * @requires $location
13777    * @requires $rootScope
13778    *
13779    * @description
13780    * When called, it scrolls to the element related to the specified `hash` or (if omitted) to the
13781    * current value of {@link ng.$location#hash $location.hash()}, according to the rules specified
13782    * in the
13783    * [HTML5 spec](http://www.w3.org/html/wg/drafts/html/master/browsers.html#the-indicated-part-of-the-document).
13784    *
13785    * It also watches the {@link ng.$location#hash $location.hash()} and automatically scrolls to
13786    * match any anchor whenever it changes. This can be disabled by calling
13787    * {@link ng.$anchorScrollProvider#disableAutoScrolling $anchorScrollProvider.disableAutoScrolling()}.
13788    *
13789    * Additionally, you can use its {@link ng.$anchorScroll#yOffset yOffset} property to specify a
13790    * vertical scroll-offset (either fixed or dynamic).
13791    *
13792    * @param {string=} hash The hash specifying the element to scroll to. If omitted, the value of
13793    *                       {@link ng.$location#hash $location.hash()} will be used.
13794    *
13795    * @property {(number|function|jqLite)} yOffset
13796    * If set, specifies a vertical scroll-offset. This is often useful when there are fixed
13797    * positioned elements at the top of the page, such as navbars, headers etc.
13798    *
13799    * `yOffset` can be specified in various ways:
13800    * - **number**: A fixed number of pixels to be used as offset.<br /><br />
13801    * - **function**: A getter function called everytime `$anchorScroll()` is executed. Must return
13802    *   a number representing the offset (in pixels).<br /><br />
13803    * - **jqLite**: A jqLite/jQuery element to be used for specifying the offset. The distance from
13804    *   the top of the page to the element's bottom will be used as offset.<br />
13805    *   **Note**: The element will be taken into account only as long as its `position` is set to
13806    *   `fixed`. This option is useful, when dealing with responsive navbars/headers that adjust
13807    *   their height and/or positioning according to the viewport's size.
13808    *
13809    * <br />
13810    * <div class="alert alert-warning">
13811    * In order for `yOffset` to work properly, scrolling should take place on the document's root and
13812    * not some child element.
13813    * </div>
13814    *
13815    * @example
13816      <example module="anchorScrollExample">
13817        <file name="index.html">
13818          <div id="scrollArea" ng-controller="ScrollController">
13819            <a ng-click="gotoBottom()">Go to bottom</a>
13820            <a id="bottom"></a> You're at the bottom!
13821          </div>
13822        </file>
13823        <file name="script.js">
13824          angular.module('anchorScrollExample', [])
13825            .controller('ScrollController', ['$scope', '$location', '$anchorScroll',
13826              function ($scope, $location, $anchorScroll) {
13827                $scope.gotoBottom = function() {
13828                  // set the location.hash to the id of
13829                  // the element you wish to scroll to.
13830                  $location.hash('bottom');
13831
13832                  // call $anchorScroll()
13833                  $anchorScroll();
13834                };
13835              }]);
13836        </file>
13837        <file name="style.css">
13838          #scrollArea {
13839            height: 280px;
13840            overflow: auto;
13841          }
13842
13843          #bottom {
13844            display: block;
13845            margin-top: 2000px;
13846          }
13847        </file>
13848      </example>
13849    *
13850    * <hr />
13851    * The example below illustrates the use of a vertical scroll-offset (specified as a fixed value).
13852    * See {@link ng.$anchorScroll#yOffset $anchorScroll.yOffset} for more details.
13853    *
13854    * @example
13855      <example module="anchorScrollOffsetExample">
13856        <file name="index.html">
13857          <div class="fixed-header" ng-controller="headerCtrl">
13858            <a href="" ng-click="gotoAnchor(x)" ng-repeat="x in [1,2,3,4,5]">
13859              Go to anchor {{x}}
13860            </a>
13861          </div>
13862          <div id="anchor{{x}}" class="anchor" ng-repeat="x in [1,2,3,4,5]">
13863            Anchor {{x}} of 5
13864          </div>
13865        </file>
13866        <file name="script.js">
13867          angular.module('anchorScrollOffsetExample', [])
13868            .run(['$anchorScroll', function($anchorScroll) {
13869              $anchorScroll.yOffset = 50;   // always scroll by 50 extra pixels
13870            }])
13871            .controller('headerCtrl', ['$anchorScroll', '$location', '$scope',
13872              function ($anchorScroll, $location, $scope) {
13873                $scope.gotoAnchor = function(x) {
13874                  var newHash = 'anchor' + x;
13875                  if ($location.hash() !== newHash) {
13876                    // set the $location.hash to `newHash` and
13877                    // $anchorScroll will automatically scroll to it
13878                    $location.hash('anchor' + x);
13879                  } else {
13880                    // call $anchorScroll() explicitly,
13881                    // since $location.hash hasn't changed
13882                    $anchorScroll();
13883                  }
13884                };
13885              }
13886            ]);
13887        </file>
13888        <file name="style.css">
13889          body {
13890            padding-top: 50px;
13891          }
13892
13893          .anchor {
13894            border: 2px dashed DarkOrchid;
13895            padding: 10px 10px 200px 10px;
13896          }
13897
13898          .fixed-header {
13899            background-color: rgba(0, 0, 0, 0.2);
13900            height: 50px;
13901            position: fixed;
13902            top: 0; left: 0; right: 0;
13903          }
13904
13905          .fixed-header > a {
13906            display: inline-block;
13907            margin: 5px 15px;
13908          }
13909        </file>
13910      </example>
13911    */
13912   this.$get = ['$window', '$location', '$rootScope', function($window, $location, $rootScope) {
13913     var document = $window.document;
13914
13915     // Helper function to get first anchor from a NodeList
13916     // (using `Array#some()` instead of `angular#forEach()` since it's more performant
13917     //  and working in all supported browsers.)
13918     function getFirstAnchor(list) {
13919       var result = null;
13920       Array.prototype.some.call(list, function(element) {
13921         if (nodeName_(element) === 'a') {
13922           result = element;
13923           return true;
13924         }
13925       });
13926       return result;
13927     }
13928
13929     function getYOffset() {
13930
13931       var offset = scroll.yOffset;
13932
13933       if (isFunction(offset)) {
13934         offset = offset();
13935       } else if (isElement(offset)) {
13936         var elem = offset[0];
13937         var style = $window.getComputedStyle(elem);
13938         if (style.position !== 'fixed') {
13939           offset = 0;
13940         } else {
13941           offset = elem.getBoundingClientRect().bottom;
13942         }
13943       } else if (!isNumber(offset)) {
13944         offset = 0;
13945       }
13946
13947       return offset;
13948     }
13949
13950     function scrollTo(elem) {
13951       if (elem) {
13952         elem.scrollIntoView();
13953
13954         var offset = getYOffset();
13955
13956         if (offset) {
13957           // `offset` is the number of pixels we should scroll UP in order to align `elem` properly.
13958           // This is true ONLY if the call to `elem.scrollIntoView()` initially aligns `elem` at the
13959           // top of the viewport.
13960           //
13961           // IF the number of pixels from the top of `elem` to the end of the page's content is less
13962           // than the height of the viewport, then `elem.scrollIntoView()` will align the `elem` some
13963           // way down the page.
13964           //
13965           // This is often the case for elements near the bottom of the page.
13966           //
13967           // In such cases we do not need to scroll the whole `offset` up, just the difference between
13968           // the top of the element and the offset, which is enough to align the top of `elem` at the
13969           // desired position.
13970           var elemTop = elem.getBoundingClientRect().top;
13971           $window.scrollBy(0, elemTop - offset);
13972         }
13973       } else {
13974         $window.scrollTo(0, 0);
13975       }
13976     }
13977
13978     function scroll(hash) {
13979       hash = isString(hash) ? hash : $location.hash();
13980       var elm;
13981
13982       // empty hash, scroll to the top of the page
13983       if (!hash) scrollTo(null);
13984
13985       // element with given id
13986       else if ((elm = document.getElementById(hash))) scrollTo(elm);
13987
13988       // first anchor with given name :-D
13989       else if ((elm = getFirstAnchor(document.getElementsByName(hash)))) scrollTo(elm);
13990
13991       // no element and hash == 'top', scroll to the top of the page
13992       else if (hash === 'top') scrollTo(null);
13993     }
13994
13995     // does not scroll when user clicks on anchor link that is currently on
13996     // (no url change, no $location.hash() change), browser native does scroll
13997     if (autoScrollingEnabled) {
13998       $rootScope.$watch(function autoScrollWatch() {return $location.hash();},
13999         function autoScrollWatchAction(newVal, oldVal) {
14000           // skip the initial scroll if $location.hash is empty
14001           if (newVal === oldVal && newVal === '') return;
14002
14003           jqLiteDocumentLoaded(function() {
14004             $rootScope.$evalAsync(scroll);
14005           });
14006         });
14007     }
14008
14009     return scroll;
14010   }];
14011 }
14012
14013 var $animateMinErr = minErr('$animate');
14014 var ELEMENT_NODE = 1;
14015 var NG_ANIMATE_CLASSNAME = 'ng-animate';
14016
14017 function mergeClasses(a,b) {
14018   if (!a && !b) return '';
14019   if (!a) return b;
14020   if (!b) return a;
14021   if (isArray(a)) a = a.join(' ');
14022   if (isArray(b)) b = b.join(' ');
14023   return a + ' ' + b;
14024 }
14025
14026 function extractElementNode(element) {
14027   for (var i = 0; i < element.length; i++) {
14028     var elm = element[i];
14029     if (elm.nodeType === ELEMENT_NODE) {
14030       return elm;
14031     }
14032   }
14033 }
14034
14035 function splitClasses(classes) {
14036   if (isString(classes)) {
14037     classes = classes.split(' ');
14038   }
14039
14040   // Use createMap() to prevent class assumptions involving property names in
14041   // Object.prototype
14042   var obj = createMap();
14043   forEach(classes, function(klass) {
14044     // sometimes the split leaves empty string values
14045     // incase extra spaces were applied to the options
14046     if (klass.length) {
14047       obj[klass] = true;
14048     }
14049   });
14050   return obj;
14051 }
14052
14053 // if any other type of options value besides an Object value is
14054 // passed into the $animate.method() animation then this helper code
14055 // will be run which will ignore it. While this patch is not the
14056 // greatest solution to this, a lot of existing plugins depend on
14057 // $animate to either call the callback (< 1.2) or return a promise
14058 // that can be changed. This helper function ensures that the options
14059 // are wiped clean incase a callback function is provided.
14060 function prepareAnimateOptions(options) {
14061   return isObject(options)
14062       ? options
14063       : {};
14064 }
14065
14066 var $$CoreAnimateRunnerProvider = function() {
14067   this.$get = ['$q', '$$rAF', function($q, $$rAF) {
14068     function AnimateRunner() {}
14069     AnimateRunner.all = noop;
14070     AnimateRunner.chain = noop;
14071     AnimateRunner.prototype = {
14072       end: noop,
14073       cancel: noop,
14074       resume: noop,
14075       pause: noop,
14076       complete: noop,
14077       then: function(pass, fail) {
14078         return $q(function(resolve) {
14079           $$rAF(function() {
14080             resolve();
14081           });
14082         }).then(pass, fail);
14083       }
14084     };
14085     return AnimateRunner;
14086   }];
14087 };
14088
14089 // this is prefixed with Core since it conflicts with
14090 // the animateQueueProvider defined in ngAnimate/animateQueue.js
14091 var $$CoreAnimateQueueProvider = function() {
14092   var postDigestQueue = new HashMap();
14093   var postDigestElements = [];
14094
14095   this.$get = ['$$AnimateRunner', '$rootScope',
14096        function($$AnimateRunner,   $rootScope) {
14097     return {
14098       enabled: noop,
14099       on: noop,
14100       off: noop,
14101       pin: noop,
14102
14103       push: function(element, event, options, domOperation) {
14104         domOperation        && domOperation();
14105
14106         options = options || {};
14107         options.from        && element.css(options.from);
14108         options.to          && element.css(options.to);
14109
14110         if (options.addClass || options.removeClass) {
14111           addRemoveClassesPostDigest(element, options.addClass, options.removeClass);
14112         }
14113
14114         return new $$AnimateRunner(); // jshint ignore:line
14115       }
14116     };
14117
14118
14119     function updateData(data, classes, value) {
14120       var changed = false;
14121       if (classes) {
14122         classes = isString(classes) ? classes.split(' ') :
14123                   isArray(classes) ? classes : [];
14124         forEach(classes, function(className) {
14125           if (className) {
14126             changed = true;
14127             data[className] = value;
14128           }
14129         });
14130       }
14131       return changed;
14132     }
14133
14134     function handleCSSClassChanges() {
14135       forEach(postDigestElements, function(element) {
14136         var data = postDigestQueue.get(element);
14137         if (data) {
14138           var existing = splitClasses(element.attr('class'));
14139           var toAdd = '';
14140           var toRemove = '';
14141           forEach(data, function(status, className) {
14142             var hasClass = !!existing[className];
14143             if (status !== hasClass) {
14144               if (status) {
14145                 toAdd += (toAdd.length ? ' ' : '') + className;
14146               } else {
14147                 toRemove += (toRemove.length ? ' ' : '') + className;
14148               }
14149             }
14150           });
14151
14152           forEach(element, function(elm) {
14153             toAdd    && jqLiteAddClass(elm, toAdd);
14154             toRemove && jqLiteRemoveClass(elm, toRemove);
14155           });
14156           postDigestQueue.remove(element);
14157         }
14158       });
14159       postDigestElements.length = 0;
14160     }
14161
14162
14163     function addRemoveClassesPostDigest(element, add, remove) {
14164       var data = postDigestQueue.get(element) || {};
14165
14166       var classesAdded = updateData(data, add, true);
14167       var classesRemoved = updateData(data, remove, false);
14168
14169       if (classesAdded || classesRemoved) {
14170
14171         postDigestQueue.put(element, data);
14172         postDigestElements.push(element);
14173
14174         if (postDigestElements.length === 1) {
14175           $rootScope.$$postDigest(handleCSSClassChanges);
14176         }
14177       }
14178     }
14179   }];
14180 };
14181
14182 /**
14183  * @ngdoc provider
14184  * @name $animateProvider
14185  *
14186  * @description
14187  * Default implementation of $animate that doesn't perform any animations, instead just
14188  * synchronously performs DOM updates and resolves the returned runner promise.
14189  *
14190  * In order to enable animations the `ngAnimate` module has to be loaded.
14191  *
14192  * To see the functional implementation check out `src/ngAnimate/animate.js`.
14193  */
14194 var $AnimateProvider = ['$provide', function($provide) {
14195   var provider = this;
14196
14197   this.$$registeredAnimations = Object.create(null);
14198
14199    /**
14200    * @ngdoc method
14201    * @name $animateProvider#register
14202    *
14203    * @description
14204    * Registers a new injectable animation factory function. The factory function produces the
14205    * animation object which contains callback functions for each event that is expected to be
14206    * animated.
14207    *
14208    *   * `eventFn`: `function(element, ... , doneFunction, options)`
14209    *   The element to animate, the `doneFunction` and the options fed into the animation. Depending
14210    *   on the type of animation additional arguments will be injected into the animation function. The
14211    *   list below explains the function signatures for the different animation methods:
14212    *
14213    *   - setClass: function(element, addedClasses, removedClasses, doneFunction, options)
14214    *   - addClass: function(element, addedClasses, doneFunction, options)
14215    *   - removeClass: function(element, removedClasses, doneFunction, options)
14216    *   - enter, leave, move: function(element, doneFunction, options)
14217    *   - animate: function(element, fromStyles, toStyles, doneFunction, options)
14218    *
14219    *   Make sure to trigger the `doneFunction` once the animation is fully complete.
14220    *
14221    * ```js
14222    *   return {
14223    *     //enter, leave, move signature
14224    *     eventFn : function(element, done, options) {
14225    *       //code to run the animation
14226    *       //once complete, then run done()
14227    *       return function endFunction(wasCancelled) {
14228    *         //code to cancel the animation
14229    *       }
14230    *     }
14231    *   }
14232    * ```
14233    *
14234    * @param {string} name The name of the animation (this is what the class-based CSS value will be compared to).
14235    * @param {Function} factory The factory function that will be executed to return the animation
14236    *                           object.
14237    */
14238   this.register = function(name, factory) {
14239     if (name && name.charAt(0) !== '.') {
14240       throw $animateMinErr('notcsel', "Expecting class selector starting with '.' got '{0}'.", name);
14241     }
14242
14243     var key = name + '-animation';
14244     provider.$$registeredAnimations[name.substr(1)] = key;
14245     $provide.factory(key, factory);
14246   };
14247
14248   /**
14249    * @ngdoc method
14250    * @name $animateProvider#classNameFilter
14251    *
14252    * @description
14253    * Sets and/or returns the CSS class regular expression that is checked when performing
14254    * an animation. Upon bootstrap the classNameFilter value is not set at all and will
14255    * therefore enable $animate to attempt to perform an animation on any element that is triggered.
14256    * When setting the `classNameFilter` value, animations will only be performed on elements
14257    * that successfully match the filter expression. This in turn can boost performance
14258    * for low-powered devices as well as applications containing a lot of structural operations.
14259    * @param {RegExp=} expression The className expression which will be checked against all animations
14260    * @return {RegExp} The current CSS className expression value. If null then there is no expression value
14261    */
14262   this.classNameFilter = function(expression) {
14263     if (arguments.length === 1) {
14264       this.$$classNameFilter = (expression instanceof RegExp) ? expression : null;
14265       if (this.$$classNameFilter) {
14266         var reservedRegex = new RegExp("(\\s+|\\/)" + NG_ANIMATE_CLASSNAME + "(\\s+|\\/)");
14267         if (reservedRegex.test(this.$$classNameFilter.toString())) {
14268           throw $animateMinErr('nongcls','$animateProvider.classNameFilter(regex) prohibits accepting a regex value which matches/contains the "{0}" CSS class.', NG_ANIMATE_CLASSNAME);
14269
14270         }
14271       }
14272     }
14273     return this.$$classNameFilter;
14274   };
14275
14276   this.$get = ['$$animateQueue', function($$animateQueue) {
14277     function domInsert(element, parentElement, afterElement) {
14278       // if for some reason the previous element was removed
14279       // from the dom sometime before this code runs then let's
14280       // just stick to using the parent element as the anchor
14281       if (afterElement) {
14282         var afterNode = extractElementNode(afterElement);
14283         if (afterNode && !afterNode.parentNode && !afterNode.previousElementSibling) {
14284           afterElement = null;
14285         }
14286       }
14287       afterElement ? afterElement.after(element) : parentElement.prepend(element);
14288     }
14289
14290     /**
14291      * @ngdoc service
14292      * @name $animate
14293      * @description The $animate service exposes a series of DOM utility methods that provide support
14294      * for animation hooks. The default behavior is the application of DOM operations, however,
14295      * when an animation is detected (and animations are enabled), $animate will do the heavy lifting
14296      * to ensure that animation runs with the triggered DOM operation.
14297      *
14298      * By default $animate doesn't trigger any animations. This is because the `ngAnimate` module isn't
14299      * included and only when it is active then the animation hooks that `$animate` triggers will be
14300      * functional. Once active then all structural `ng-` directives will trigger animations as they perform
14301      * their DOM-related operations (enter, leave and move). Other directives such as `ngClass`,
14302      * `ngShow`, `ngHide` and `ngMessages` also provide support for animations.
14303      *
14304      * It is recommended that the`$animate` service is always used when executing DOM-related procedures within directives.
14305      *
14306      * To learn more about enabling animation support, click here to visit the
14307      * {@link ngAnimate ngAnimate module page}.
14308      */
14309     return {
14310       // we don't call it directly since non-existant arguments may
14311       // be interpreted as null within the sub enabled function
14312
14313       /**
14314        *
14315        * @ngdoc method
14316        * @name $animate#on
14317        * @kind function
14318        * @description Sets up an event listener to fire whenever the animation event (enter, leave, move, etc...)
14319        *    has fired on the given element or among any of its children. Once the listener is fired, the provided callback
14320        *    is fired with the following params:
14321        *
14322        * ```js
14323        * $animate.on('enter', container,
14324        *    function callback(element, phase) {
14325        *      // cool we detected an enter animation within the container
14326        *    }
14327        * );
14328        * ```
14329        *
14330        * @param {string} event the animation event that will be captured (e.g. enter, leave, move, addClass, removeClass, etc...)
14331        * @param {DOMElement} container the container element that will capture each of the animation events that are fired on itself
14332        *     as well as among its children
14333        * @param {Function} callback the callback function that will be fired when the listener is triggered
14334        *
14335        * The arguments present in the callback function are:
14336        * * `element` - The captured DOM element that the animation was fired on.
14337        * * `phase` - The phase of the animation. The two possible phases are **start** (when the animation starts) and **close** (when it ends).
14338        */
14339       on: $$animateQueue.on,
14340
14341       /**
14342        *
14343        * @ngdoc method
14344        * @name $animate#off
14345        * @kind function
14346        * @description Deregisters an event listener based on the event which has been associated with the provided element. This method
14347        * can be used in three different ways depending on the arguments:
14348        *
14349        * ```js
14350        * // remove all the animation event listeners listening for `enter`
14351        * $animate.off('enter');
14352        *
14353        * // remove all the animation event listeners listening for `enter` on the given element and its children
14354        * $animate.off('enter', container);
14355        *
14356        * // remove the event listener function provided by `listenerFn` that is set
14357        * // to listen for `enter` on the given `element` as well as its children
14358        * $animate.off('enter', container, callback);
14359        * ```
14360        *
14361        * @param {string} event the animation event (e.g. enter, leave, move, addClass, removeClass, etc...)
14362        * @param {DOMElement=} container the container element the event listener was placed on
14363        * @param {Function=} callback the callback function that was registered as the listener
14364        */
14365       off: $$animateQueue.off,
14366
14367       /**
14368        * @ngdoc method
14369        * @name $animate#pin
14370        * @kind function
14371        * @description Associates the provided element with a host parent element to allow the element to be animated even if it exists
14372        *    outside of the DOM structure of the Angular application. By doing so, any animation triggered via `$animate` can be issued on the
14373        *    element despite being outside the realm of the application or within another application. Say for example if the application
14374        *    was bootstrapped on an element that is somewhere inside of the `<body>` tag, but we wanted to allow for an element to be situated
14375        *    as a direct child of `document.body`, then this can be achieved by pinning the element via `$animate.pin(element)`. Keep in mind
14376        *    that calling `$animate.pin(element, parentElement)` will not actually insert into the DOM anywhere; it will just create the association.
14377        *
14378        *    Note that this feature is only active when the `ngAnimate` module is used.
14379        *
14380        * @param {DOMElement} element the external element that will be pinned
14381        * @param {DOMElement} parentElement the host parent element that will be associated with the external element
14382        */
14383       pin: $$animateQueue.pin,
14384
14385       /**
14386        *
14387        * @ngdoc method
14388        * @name $animate#enabled
14389        * @kind function
14390        * @description Used to get and set whether animations are enabled or not on the entire application or on an element and its children. This
14391        * function can be called in four ways:
14392        *
14393        * ```js
14394        * // returns true or false
14395        * $animate.enabled();
14396        *
14397        * // changes the enabled state for all animations
14398        * $animate.enabled(false);
14399        * $animate.enabled(true);
14400        *
14401        * // returns true or false if animations are enabled for an element
14402        * $animate.enabled(element);
14403        *
14404        * // changes the enabled state for an element and its children
14405        * $animate.enabled(element, true);
14406        * $animate.enabled(element, false);
14407        * ```
14408        *
14409        * @param {DOMElement=} element the element that will be considered for checking/setting the enabled state
14410        * @param {boolean=} enabled whether or not the animations will be enabled for the element
14411        *
14412        * @return {boolean} whether or not animations are enabled
14413        */
14414       enabled: $$animateQueue.enabled,
14415
14416       /**
14417        * @ngdoc method
14418        * @name $animate#cancel
14419        * @kind function
14420        * @description Cancels the provided animation.
14421        *
14422        * @param {Promise} animationPromise The animation promise that is returned when an animation is started.
14423        */
14424       cancel: function(runner) {
14425         runner.end && runner.end();
14426       },
14427
14428       /**
14429        *
14430        * @ngdoc method
14431        * @name $animate#enter
14432        * @kind function
14433        * @description Inserts the element into the DOM either after the `after` element (if provided) or
14434        *   as the first child within the `parent` element and then triggers an animation.
14435        *   A promise is returned that will be resolved during the next digest once the animation
14436        *   has completed.
14437        *
14438        * @param {DOMElement} element the element which will be inserted into the DOM
14439        * @param {DOMElement} parent the parent element which will append the element as
14440        *   a child (so long as the after element is not present)
14441        * @param {DOMElement=} after the sibling element after which the element will be appended
14442        * @param {object=} options an optional collection of options/styles that will be applied to the element
14443        *
14444        * @return {Promise} the animation callback promise
14445        */
14446       enter: function(element, parent, after, options) {
14447         parent = parent && jqLite(parent);
14448         after = after && jqLite(after);
14449         parent = parent || after.parent();
14450         domInsert(element, parent, after);
14451         return $$animateQueue.push(element, 'enter', prepareAnimateOptions(options));
14452       },
14453
14454       /**
14455        *
14456        * @ngdoc method
14457        * @name $animate#move
14458        * @kind function
14459        * @description Inserts (moves) the element into its new position in the DOM either after
14460        *   the `after` element (if provided) or as the first child within the `parent` element
14461        *   and then triggers an animation. A promise is returned that will be resolved
14462        *   during the next digest once the animation has completed.
14463        *
14464        * @param {DOMElement} element the element which will be moved into the new DOM position
14465        * @param {DOMElement} parent the parent element which will append the element as
14466        *   a child (so long as the after element is not present)
14467        * @param {DOMElement=} after the sibling element after which the element will be appended
14468        * @param {object=} options an optional collection of options/styles that will be applied to the element
14469        *
14470        * @return {Promise} the animation callback promise
14471        */
14472       move: function(element, parent, after, options) {
14473         parent = parent && jqLite(parent);
14474         after = after && jqLite(after);
14475         parent = parent || after.parent();
14476         domInsert(element, parent, after);
14477         return $$animateQueue.push(element, 'move', prepareAnimateOptions(options));
14478       },
14479
14480       /**
14481        * @ngdoc method
14482        * @name $animate#leave
14483        * @kind function
14484        * @description Triggers an animation and then removes the element from the DOM.
14485        * When the function is called a promise is returned that will be resolved during the next
14486        * digest once the animation has completed.
14487        *
14488        * @param {DOMElement} element the element which will be removed from the DOM
14489        * @param {object=} options an optional collection of options/styles that will be applied to the element
14490        *
14491        * @return {Promise} the animation callback promise
14492        */
14493       leave: function(element, options) {
14494         return $$animateQueue.push(element, 'leave', prepareAnimateOptions(options), function() {
14495           element.remove();
14496         });
14497       },
14498
14499       /**
14500        * @ngdoc method
14501        * @name $animate#addClass
14502        * @kind function
14503        *
14504        * @description Triggers an addClass animation surrounding the addition of the provided CSS class(es). Upon
14505        *   execution, the addClass operation will only be handled after the next digest and it will not trigger an
14506        *   animation if element already contains the CSS class or if the class is removed at a later step.
14507        *   Note that class-based animations are treated differently compared to structural animations
14508        *   (like enter, move and leave) since the CSS classes may be added/removed at different points
14509        *   depending if CSS or JavaScript animations are used.
14510        *
14511        * @param {DOMElement} element the element which the CSS classes will be applied to
14512        * @param {string} className the CSS class(es) that will be added (multiple classes are separated via spaces)
14513        * @param {object=} options an optional collection of options/styles that will be applied to the element
14514        *
14515        * @return {Promise} the animation callback promise
14516        */
14517       addClass: function(element, className, options) {
14518         options = prepareAnimateOptions(options);
14519         options.addClass = mergeClasses(options.addclass, className);
14520         return $$animateQueue.push(element, 'addClass', options);
14521       },
14522
14523       /**
14524        * @ngdoc method
14525        * @name $animate#removeClass
14526        * @kind function
14527        *
14528        * @description Triggers a removeClass animation surrounding the removal of the provided CSS class(es). Upon
14529        *   execution, the removeClass operation will only be handled after the next digest and it will not trigger an
14530        *   animation if element does not contain the CSS class or if the class is added at a later step.
14531        *   Note that class-based animations are treated differently compared to structural animations
14532        *   (like enter, move and leave) since the CSS classes may be added/removed at different points
14533        *   depending if CSS or JavaScript animations are used.
14534        *
14535        * @param {DOMElement} element the element which the CSS classes will be applied to
14536        * @param {string} className the CSS class(es) that will be removed (multiple classes are separated via spaces)
14537        * @param {object=} options an optional collection of options/styles that will be applied to the element
14538        *
14539        * @return {Promise} the animation callback promise
14540        */
14541       removeClass: function(element, className, options) {
14542         options = prepareAnimateOptions(options);
14543         options.removeClass = mergeClasses(options.removeClass, className);
14544         return $$animateQueue.push(element, 'removeClass', options);
14545       },
14546
14547       /**
14548        * @ngdoc method
14549        * @name $animate#setClass
14550        * @kind function
14551        *
14552        * @description Performs both the addition and removal of a CSS classes on an element and (during the process)
14553        *    triggers an animation surrounding the class addition/removal. Much like `$animate.addClass` and
14554        *    `$animate.removeClass`, `setClass` will only evaluate the classes being added/removed once a digest has
14555        *    passed. Note that class-based animations are treated differently compared to structural animations
14556        *    (like enter, move and leave) since the CSS classes may be added/removed at different points
14557        *    depending if CSS or JavaScript animations are used.
14558        *
14559        * @param {DOMElement} element the element which the CSS classes will be applied to
14560        * @param {string} add the CSS class(es) that will be added (multiple classes are separated via spaces)
14561        * @param {string} remove the CSS class(es) that will be removed (multiple classes are separated via spaces)
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       setClass: function(element, add, remove, options) {
14567         options = prepareAnimateOptions(options);
14568         options.addClass = mergeClasses(options.addClass, add);
14569         options.removeClass = mergeClasses(options.removeClass, remove);
14570         return $$animateQueue.push(element, 'setClass', options);
14571       },
14572
14573       /**
14574        * @ngdoc method
14575        * @name $animate#animate
14576        * @kind function
14577        *
14578        * @description Performs an inline animation on the element which applies the provided to and from CSS styles to the element.
14579        * If any detected CSS transition, keyframe or JavaScript matches the provided className value then the animation will take
14580        * on the provided styles. For example, if a transition animation is set for the given className then the provided from and
14581        * to styles will be applied alongside the given transition. If a JavaScript animation is detected then the provided styles
14582        * will be given in as function paramters into the `animate` method (or as apart of the `options` parameter).
14583        *
14584        * @param {DOMElement} element the element which the CSS styles will be applied to
14585        * @param {object} from the from (starting) CSS styles that will be applied to the element and across the animation.
14586        * @param {object} to the to (destination) CSS styles that will be applied to the element and across the animation.
14587        * @param {string=} className an optional CSS class that will be applied to the element for the duration of the animation. If
14588        *    this value is left as empty then a CSS class of `ng-inline-animate` will be applied to the element.
14589        *    (Note that if no animation is detected then this value will not be appplied to the element.)
14590        * @param {object=} options an optional collection of options/styles that will be applied to the element
14591        *
14592        * @return {Promise} the animation callback promise
14593        */
14594       animate: function(element, from, to, className, options) {
14595         options = prepareAnimateOptions(options);
14596         options.from = options.from ? extend(options.from, from) : from;
14597         options.to   = options.to   ? extend(options.to, to)     : to;
14598
14599         className = className || 'ng-inline-animate';
14600         options.tempClasses = mergeClasses(options.tempClasses, className);
14601         return $$animateQueue.push(element, 'animate', options);
14602       }
14603     };
14604   }];
14605 }];
14606
14607 /**
14608  * @ngdoc service
14609  * @name $animateCss
14610  * @kind object
14611  *
14612  * @description
14613  * This is the core version of `$animateCss`. By default, only when the `ngAnimate` is included,
14614  * then the `$animateCss` service will actually perform animations.
14615  *
14616  * Click here {@link ngAnimate.$animateCss to read the documentation for $animateCss}.
14617  */
14618 var $CoreAnimateCssProvider = function() {
14619   this.$get = ['$$rAF', '$q', function($$rAF, $q) {
14620
14621     var RAFPromise = function() {};
14622     RAFPromise.prototype = {
14623       done: function(cancel) {
14624         this.defer && this.defer[cancel === true ? 'reject' : 'resolve']();
14625       },
14626       end: function() {
14627         this.done();
14628       },
14629       cancel: function() {
14630         this.done(true);
14631       },
14632       getPromise: function() {
14633         if (!this.defer) {
14634           this.defer = $q.defer();
14635         }
14636         return this.defer.promise;
14637       },
14638       then: function(f1,f2) {
14639         return this.getPromise().then(f1,f2);
14640       },
14641       'catch': function(f1) {
14642         return this.getPromise()['catch'](f1);
14643       },
14644       'finally': function(f1) {
14645         return this.getPromise()['finally'](f1);
14646       }
14647     };
14648
14649     return function(element, options) {
14650       // there is no point in applying the styles since
14651       // there is no animation that goes on at all in
14652       // this version of $animateCss.
14653       if (options.cleanupStyles) {
14654         options.from = options.to = null;
14655       }
14656
14657       if (options.from) {
14658         element.css(options.from);
14659         options.from = null;
14660       }
14661
14662       var closed, runner = new RAFPromise();
14663       return {
14664         start: run,
14665         end: run
14666       };
14667
14668       function run() {
14669         $$rAF(function() {
14670           close();
14671           if (!closed) {
14672             runner.done();
14673           }
14674           closed = true;
14675         });
14676         return runner;
14677       }
14678
14679       function close() {
14680         if (options.addClass) {
14681           element.addClass(options.addClass);
14682           options.addClass = null;
14683         }
14684         if (options.removeClass) {
14685           element.removeClass(options.removeClass);
14686           options.removeClass = null;
14687         }
14688         if (options.to) {
14689           element.css(options.to);
14690           options.to = null;
14691         }
14692       }
14693     };
14694   }];
14695 };
14696
14697 /* global stripHash: true */
14698
14699 /**
14700  * ! This is a private undocumented service !
14701  *
14702  * @name $browser
14703  * @requires $log
14704  * @description
14705  * This object has two goals:
14706  *
14707  * - hide all the global state in the browser caused by the window object
14708  * - abstract away all the browser specific features and inconsistencies
14709  *
14710  * For tests we provide {@link ngMock.$browser mock implementation} of the `$browser`
14711  * service, which can be used for convenient testing of the application without the interaction with
14712  * the real browser apis.
14713  */
14714 /**
14715  * @param {object} window The global window object.
14716  * @param {object} document jQuery wrapped document.
14717  * @param {object} $log window.console or an object with the same interface.
14718  * @param {object} $sniffer $sniffer service
14719  */
14720 function Browser(window, document, $log, $sniffer) {
14721   var self = this,
14722       rawDocument = document[0],
14723       location = window.location,
14724       history = window.history,
14725       setTimeout = window.setTimeout,
14726       clearTimeout = window.clearTimeout,
14727       pendingDeferIds = {};
14728
14729   self.isMock = false;
14730
14731   var outstandingRequestCount = 0;
14732   var outstandingRequestCallbacks = [];
14733
14734   // TODO(vojta): remove this temporary api
14735   self.$$completeOutstandingRequest = completeOutstandingRequest;
14736   self.$$incOutstandingRequestCount = function() { outstandingRequestCount++; };
14737
14738   /**
14739    * Executes the `fn` function(supports currying) and decrements the `outstandingRequestCallbacks`
14740    * counter. If the counter reaches 0, all the `outstandingRequestCallbacks` are executed.
14741    */
14742   function completeOutstandingRequest(fn) {
14743     try {
14744       fn.apply(null, sliceArgs(arguments, 1));
14745     } finally {
14746       outstandingRequestCount--;
14747       if (outstandingRequestCount === 0) {
14748         while (outstandingRequestCallbacks.length) {
14749           try {
14750             outstandingRequestCallbacks.pop()();
14751           } catch (e) {
14752             $log.error(e);
14753           }
14754         }
14755       }
14756     }
14757   }
14758
14759   function getHash(url) {
14760     var index = url.indexOf('#');
14761     return index === -1 ? '' : url.substr(index);
14762   }
14763
14764   /**
14765    * @private
14766    * Note: this method is used only by scenario runner
14767    * TODO(vojta): prefix this method with $$ ?
14768    * @param {function()} callback Function that will be called when no outstanding request
14769    */
14770   self.notifyWhenNoOutstandingRequests = function(callback) {
14771     if (outstandingRequestCount === 0) {
14772       callback();
14773     } else {
14774       outstandingRequestCallbacks.push(callback);
14775     }
14776   };
14777
14778   //////////////////////////////////////////////////////////////
14779   // URL API
14780   //////////////////////////////////////////////////////////////
14781
14782   var cachedState, lastHistoryState,
14783       lastBrowserUrl = location.href,
14784       baseElement = document.find('base'),
14785       pendingLocation = null;
14786
14787   cacheState();
14788   lastHistoryState = cachedState;
14789
14790   /**
14791    * @name $browser#url
14792    *
14793    * @description
14794    * GETTER:
14795    * Without any argument, this method just returns current value of location.href.
14796    *
14797    * SETTER:
14798    * With at least one argument, this method sets url to new value.
14799    * If html5 history api supported, pushState/replaceState is used, otherwise
14800    * location.href/location.replace is used.
14801    * Returns its own instance to allow chaining
14802    *
14803    * NOTE: this api is intended for use only by the $location service. Please use the
14804    * {@link ng.$location $location service} to change url.
14805    *
14806    * @param {string} url New url (when used as setter)
14807    * @param {boolean=} replace Should new url replace current history record?
14808    * @param {object=} state object to use with pushState/replaceState
14809    */
14810   self.url = function(url, replace, state) {
14811     // In modern browsers `history.state` is `null` by default; treating it separately
14812     // from `undefined` would cause `$browser.url('/foo')` to change `history.state`
14813     // to undefined via `pushState`. Instead, let's change `undefined` to `null` here.
14814     if (isUndefined(state)) {
14815       state = null;
14816     }
14817
14818     // Android Browser BFCache causes location, history reference to become stale.
14819     if (location !== window.location) location = window.location;
14820     if (history !== window.history) history = window.history;
14821
14822     // setter
14823     if (url) {
14824       var sameState = lastHistoryState === state;
14825
14826       // Don't change anything if previous and current URLs and states match. This also prevents
14827       // IE<10 from getting into redirect loop when in LocationHashbangInHtml5Url mode.
14828       // See https://github.com/angular/angular.js/commit/ffb2701
14829       if (lastBrowserUrl === url && (!$sniffer.history || sameState)) {
14830         return self;
14831       }
14832       var sameBase = lastBrowserUrl && stripHash(lastBrowserUrl) === stripHash(url);
14833       lastBrowserUrl = url;
14834       lastHistoryState = state;
14835       // Don't use history API if only the hash changed
14836       // due to a bug in IE10/IE11 which leads
14837       // to not firing a `hashchange` nor `popstate` event
14838       // in some cases (see #9143).
14839       if ($sniffer.history && (!sameBase || !sameState)) {
14840         history[replace ? 'replaceState' : 'pushState'](state, '', url);
14841         cacheState();
14842         // Do the assignment again so that those two variables are referentially identical.
14843         lastHistoryState = cachedState;
14844       } else {
14845         if (!sameBase || pendingLocation) {
14846           pendingLocation = url;
14847         }
14848         if (replace) {
14849           location.replace(url);
14850         } else if (!sameBase) {
14851           location.href = url;
14852         } else {
14853           location.hash = getHash(url);
14854         }
14855         if (location.href !== url) {
14856           pendingLocation = url;
14857         }
14858       }
14859       return self;
14860     // getter
14861     } else {
14862       // - pendingLocation is needed as browsers don't allow to read out
14863       //   the new location.href if a reload happened or if there is a bug like in iOS 9 (see
14864       //   https://openradar.appspot.com/22186109).
14865       // - the replacement is a workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=407172
14866       return pendingLocation || location.href.replace(/%27/g,"'");
14867     }
14868   };
14869
14870   /**
14871    * @name $browser#state
14872    *
14873    * @description
14874    * This method is a getter.
14875    *
14876    * Return history.state or null if history.state is undefined.
14877    *
14878    * @returns {object} state
14879    */
14880   self.state = function() {
14881     return cachedState;
14882   };
14883
14884   var urlChangeListeners = [],
14885       urlChangeInit = false;
14886
14887   function cacheStateAndFireUrlChange() {
14888     pendingLocation = null;
14889     cacheState();
14890     fireUrlChange();
14891   }
14892
14893   function getCurrentState() {
14894     try {
14895       return history.state;
14896     } catch (e) {
14897       // MSIE can reportedly throw when there is no state (UNCONFIRMED).
14898     }
14899   }
14900
14901   // This variable should be used *only* inside the cacheState function.
14902   var lastCachedState = null;
14903   function cacheState() {
14904     // This should be the only place in $browser where `history.state` is read.
14905     cachedState = getCurrentState();
14906     cachedState = isUndefined(cachedState) ? null : cachedState;
14907
14908     // Prevent callbacks fo fire twice if both hashchange & popstate were fired.
14909     if (equals(cachedState, lastCachedState)) {
14910       cachedState = lastCachedState;
14911     }
14912     lastCachedState = cachedState;
14913   }
14914
14915   function fireUrlChange() {
14916     if (lastBrowserUrl === self.url() && lastHistoryState === cachedState) {
14917       return;
14918     }
14919
14920     lastBrowserUrl = self.url();
14921     lastHistoryState = cachedState;
14922     forEach(urlChangeListeners, function(listener) {
14923       listener(self.url(), cachedState);
14924     });
14925   }
14926
14927   /**
14928    * @name $browser#onUrlChange
14929    *
14930    * @description
14931    * Register callback function that will be called, when url changes.
14932    *
14933    * It's only called when the url is changed from outside of angular:
14934    * - user types different url into address bar
14935    * - user clicks on history (forward/back) button
14936    * - user clicks on a link
14937    *
14938    * It's not called when url is changed by $browser.url() method
14939    *
14940    * The listener gets called with new url as parameter.
14941    *
14942    * NOTE: this api is intended for use only by the $location service. Please use the
14943    * {@link ng.$location $location service} to monitor url changes in angular apps.
14944    *
14945    * @param {function(string)} listener Listener function to be called when url changes.
14946    * @return {function(string)} Returns the registered listener fn - handy if the fn is anonymous.
14947    */
14948   self.onUrlChange = function(callback) {
14949     // TODO(vojta): refactor to use node's syntax for events
14950     if (!urlChangeInit) {
14951       // We listen on both (hashchange/popstate) when available, as some browsers (e.g. Opera)
14952       // don't fire popstate when user change the address bar and don't fire hashchange when url
14953       // changed by push/replaceState
14954
14955       // html5 history api - popstate event
14956       if ($sniffer.history) jqLite(window).on('popstate', cacheStateAndFireUrlChange);
14957       // hashchange event
14958       jqLite(window).on('hashchange', cacheStateAndFireUrlChange);
14959
14960       urlChangeInit = true;
14961     }
14962
14963     urlChangeListeners.push(callback);
14964     return callback;
14965   };
14966
14967   /**
14968    * @private
14969    * Remove popstate and hashchange handler from window.
14970    *
14971    * NOTE: this api is intended for use only by $rootScope.
14972    */
14973   self.$$applicationDestroyed = function() {
14974     jqLite(window).off('hashchange popstate', cacheStateAndFireUrlChange);
14975   };
14976
14977   /**
14978    * Checks whether the url has changed outside of Angular.
14979    * Needs to be exported to be able to check for changes that have been done in sync,
14980    * as hashchange/popstate events fire in async.
14981    */
14982   self.$$checkUrlChange = fireUrlChange;
14983
14984   //////////////////////////////////////////////////////////////
14985   // Misc API
14986   //////////////////////////////////////////////////////////////
14987
14988   /**
14989    * @name $browser#baseHref
14990    *
14991    * @description
14992    * Returns current <base href>
14993    * (always relative - without domain)
14994    *
14995    * @returns {string} The current base href
14996    */
14997   self.baseHref = function() {
14998     var href = baseElement.attr('href');
14999     return href ? href.replace(/^(https?\:)?\/\/[^\/]*/, '') : '';
15000   };
15001
15002   /**
15003    * @name $browser#defer
15004    * @param {function()} fn A function, who's execution should be deferred.
15005    * @param {number=} [delay=0] of milliseconds to defer the function execution.
15006    * @returns {*} DeferId that can be used to cancel the task via `$browser.defer.cancel()`.
15007    *
15008    * @description
15009    * Executes a fn asynchronously via `setTimeout(fn, delay)`.
15010    *
15011    * Unlike when calling `setTimeout` directly, in test this function is mocked and instead of using
15012    * `setTimeout` in tests, the fns are queued in an array, which can be programmatically flushed
15013    * via `$browser.defer.flush()`.
15014    *
15015    */
15016   self.defer = function(fn, delay) {
15017     var timeoutId;
15018     outstandingRequestCount++;
15019     timeoutId = setTimeout(function() {
15020       delete pendingDeferIds[timeoutId];
15021       completeOutstandingRequest(fn);
15022     }, delay || 0);
15023     pendingDeferIds[timeoutId] = true;
15024     return timeoutId;
15025   };
15026
15027
15028   /**
15029    * @name $browser#defer.cancel
15030    *
15031    * @description
15032    * Cancels a deferred task identified with `deferId`.
15033    *
15034    * @param {*} deferId Token returned by the `$browser.defer` function.
15035    * @returns {boolean} Returns `true` if the task hasn't executed yet and was successfully
15036    *                    canceled.
15037    */
15038   self.defer.cancel = function(deferId) {
15039     if (pendingDeferIds[deferId]) {
15040       delete pendingDeferIds[deferId];
15041       clearTimeout(deferId);
15042       completeOutstandingRequest(noop);
15043       return true;
15044     }
15045     return false;
15046   };
15047
15048 }
15049
15050 function $BrowserProvider() {
15051   this.$get = ['$window', '$log', '$sniffer', '$document',
15052       function($window, $log, $sniffer, $document) {
15053         return new Browser($window, $document, $log, $sniffer);
15054       }];
15055 }
15056
15057 /**
15058  * @ngdoc service
15059  * @name $cacheFactory
15060  *
15061  * @description
15062  * Factory that constructs {@link $cacheFactory.Cache Cache} objects and gives access to
15063  * them.
15064  *
15065  * ```js
15066  *
15067  *  var cache = $cacheFactory('cacheId');
15068  *  expect($cacheFactory.get('cacheId')).toBe(cache);
15069  *  expect($cacheFactory.get('noSuchCacheId')).not.toBeDefined();
15070  *
15071  *  cache.put("key", "value");
15072  *  cache.put("another key", "another value");
15073  *
15074  *  // We've specified no options on creation
15075  *  expect(cache.info()).toEqual({id: 'cacheId', size: 2});
15076  *
15077  * ```
15078  *
15079  *
15080  * @param {string} cacheId Name or id of the newly created cache.
15081  * @param {object=} options Options object that specifies the cache behavior. Properties:
15082  *
15083  *   - `{number=}` `capacity` — turns the cache into LRU cache.
15084  *
15085  * @returns {object} Newly created cache object with the following set of methods:
15086  *
15087  * - `{object}` `info()` — Returns id, size, and options of cache.
15088  * - `{{*}}` `put({string} key, {*} value)` — Puts a new key-value pair into the cache and returns
15089  *   it.
15090  * - `{{*}}` `get({string} key)` — Returns cached value for `key` or undefined for cache miss.
15091  * - `{void}` `remove({string} key)` — Removes a key-value pair from the cache.
15092  * - `{void}` `removeAll()` — Removes all cached values.
15093  * - `{void}` `destroy()` — Removes references to this cache from $cacheFactory.
15094  *
15095  * @example
15096    <example module="cacheExampleApp">
15097      <file name="index.html">
15098        <div ng-controller="CacheController">
15099          <input ng-model="newCacheKey" placeholder="Key">
15100          <input ng-model="newCacheValue" placeholder="Value">
15101          <button ng-click="put(newCacheKey, newCacheValue)">Cache</button>
15102
15103          <p ng-if="keys.length">Cached Values</p>
15104          <div ng-repeat="key in keys">
15105            <span ng-bind="key"></span>
15106            <span>: </span>
15107            <b ng-bind="cache.get(key)"></b>
15108          </div>
15109
15110          <p>Cache Info</p>
15111          <div ng-repeat="(key, value) in cache.info()">
15112            <span ng-bind="key"></span>
15113            <span>: </span>
15114            <b ng-bind="value"></b>
15115          </div>
15116        </div>
15117      </file>
15118      <file name="script.js">
15119        angular.module('cacheExampleApp', []).
15120          controller('CacheController', ['$scope', '$cacheFactory', function($scope, $cacheFactory) {
15121            $scope.keys = [];
15122            $scope.cache = $cacheFactory('cacheId');
15123            $scope.put = function(key, value) {
15124              if (angular.isUndefined($scope.cache.get(key))) {
15125                $scope.keys.push(key);
15126              }
15127              $scope.cache.put(key, angular.isUndefined(value) ? null : value);
15128            };
15129          }]);
15130      </file>
15131      <file name="style.css">
15132        p {
15133          margin: 10px 0 3px;
15134        }
15135      </file>
15136    </example>
15137  */
15138 function $CacheFactoryProvider() {
15139
15140   this.$get = function() {
15141     var caches = {};
15142
15143     function cacheFactory(cacheId, options) {
15144       if (cacheId in caches) {
15145         throw minErr('$cacheFactory')('iid', "CacheId '{0}' is already taken!", cacheId);
15146       }
15147
15148       var size = 0,
15149           stats = extend({}, options, {id: cacheId}),
15150           data = createMap(),
15151           capacity = (options && options.capacity) || Number.MAX_VALUE,
15152           lruHash = createMap(),
15153           freshEnd = null,
15154           staleEnd = null;
15155
15156       /**
15157        * @ngdoc type
15158        * @name $cacheFactory.Cache
15159        *
15160        * @description
15161        * A cache object used to store and retrieve data, primarily used by
15162        * {@link $http $http} and the {@link ng.directive:script script} directive to cache
15163        * templates and other data.
15164        *
15165        * ```js
15166        *  angular.module('superCache')
15167        *    .factory('superCache', ['$cacheFactory', function($cacheFactory) {
15168        *      return $cacheFactory('super-cache');
15169        *    }]);
15170        * ```
15171        *
15172        * Example test:
15173        *
15174        * ```js
15175        *  it('should behave like a cache', inject(function(superCache) {
15176        *    superCache.put('key', 'value');
15177        *    superCache.put('another key', 'another value');
15178        *
15179        *    expect(superCache.info()).toEqual({
15180        *      id: 'super-cache',
15181        *      size: 2
15182        *    });
15183        *
15184        *    superCache.remove('another key');
15185        *    expect(superCache.get('another key')).toBeUndefined();
15186        *
15187        *    superCache.removeAll();
15188        *    expect(superCache.info()).toEqual({
15189        *      id: 'super-cache',
15190        *      size: 0
15191        *    });
15192        *  }));
15193        * ```
15194        */
15195       return caches[cacheId] = {
15196
15197         /**
15198          * @ngdoc method
15199          * @name $cacheFactory.Cache#put
15200          * @kind function
15201          *
15202          * @description
15203          * Inserts a named entry into the {@link $cacheFactory.Cache Cache} object to be
15204          * retrieved later, and incrementing the size of the cache if the key was not already
15205          * present in the cache. If behaving like an LRU cache, it will also remove stale
15206          * entries from the set.
15207          *
15208          * It will not insert undefined values into the cache.
15209          *
15210          * @param {string} key the key under which the cached data is stored.
15211          * @param {*} value the value to store alongside the key. If it is undefined, the key
15212          *    will not be stored.
15213          * @returns {*} the value stored.
15214          */
15215         put: function(key, value) {
15216           if (isUndefined(value)) return;
15217           if (capacity < Number.MAX_VALUE) {
15218             var lruEntry = lruHash[key] || (lruHash[key] = {key: key});
15219
15220             refresh(lruEntry);
15221           }
15222
15223           if (!(key in data)) size++;
15224           data[key] = value;
15225
15226           if (size > capacity) {
15227             this.remove(staleEnd.key);
15228           }
15229
15230           return value;
15231         },
15232
15233         /**
15234          * @ngdoc method
15235          * @name $cacheFactory.Cache#get
15236          * @kind function
15237          *
15238          * @description
15239          * Retrieves named data stored in the {@link $cacheFactory.Cache Cache} object.
15240          *
15241          * @param {string} key the key of the data to be retrieved
15242          * @returns {*} the value stored.
15243          */
15244         get: function(key) {
15245           if (capacity < Number.MAX_VALUE) {
15246             var lruEntry = lruHash[key];
15247
15248             if (!lruEntry) return;
15249
15250             refresh(lruEntry);
15251           }
15252
15253           return data[key];
15254         },
15255
15256
15257         /**
15258          * @ngdoc method
15259          * @name $cacheFactory.Cache#remove
15260          * @kind function
15261          *
15262          * @description
15263          * Removes an entry from the {@link $cacheFactory.Cache Cache} object.
15264          *
15265          * @param {string} key the key of the entry to be removed
15266          */
15267         remove: function(key) {
15268           if (capacity < Number.MAX_VALUE) {
15269             var lruEntry = lruHash[key];
15270
15271             if (!lruEntry) return;
15272
15273             if (lruEntry == freshEnd) freshEnd = lruEntry.p;
15274             if (lruEntry == staleEnd) staleEnd = lruEntry.n;
15275             link(lruEntry.n,lruEntry.p);
15276
15277             delete lruHash[key];
15278           }
15279
15280           if (!(key in data)) return;
15281
15282           delete data[key];
15283           size--;
15284         },
15285
15286
15287         /**
15288          * @ngdoc method
15289          * @name $cacheFactory.Cache#removeAll
15290          * @kind function
15291          *
15292          * @description
15293          * Clears the cache object of any entries.
15294          */
15295         removeAll: function() {
15296           data = createMap();
15297           size = 0;
15298           lruHash = createMap();
15299           freshEnd = staleEnd = null;
15300         },
15301
15302
15303         /**
15304          * @ngdoc method
15305          * @name $cacheFactory.Cache#destroy
15306          * @kind function
15307          *
15308          * @description
15309          * Destroys the {@link $cacheFactory.Cache Cache} object entirely,
15310          * removing it from the {@link $cacheFactory $cacheFactory} set.
15311          */
15312         destroy: function() {
15313           data = null;
15314           stats = null;
15315           lruHash = null;
15316           delete caches[cacheId];
15317         },
15318
15319
15320         /**
15321          * @ngdoc method
15322          * @name $cacheFactory.Cache#info
15323          * @kind function
15324          *
15325          * @description
15326          * Retrieve information regarding a particular {@link $cacheFactory.Cache Cache}.
15327          *
15328          * @returns {object} an object with the following properties:
15329          *   <ul>
15330          *     <li>**id**: the id of the cache instance</li>
15331          *     <li>**size**: the number of entries kept in the cache instance</li>
15332          *     <li>**...**: any additional properties from the options object when creating the
15333          *       cache.</li>
15334          *   </ul>
15335          */
15336         info: function() {
15337           return extend({}, stats, {size: size});
15338         }
15339       };
15340
15341
15342       /**
15343        * makes the `entry` the freshEnd of the LRU linked list
15344        */
15345       function refresh(entry) {
15346         if (entry != freshEnd) {
15347           if (!staleEnd) {
15348             staleEnd = entry;
15349           } else if (staleEnd == entry) {
15350             staleEnd = entry.n;
15351           }
15352
15353           link(entry.n, entry.p);
15354           link(entry, freshEnd);
15355           freshEnd = entry;
15356           freshEnd.n = null;
15357         }
15358       }
15359
15360
15361       /**
15362        * bidirectionally links two entries of the LRU linked list
15363        */
15364       function link(nextEntry, prevEntry) {
15365         if (nextEntry != prevEntry) {
15366           if (nextEntry) nextEntry.p = prevEntry; //p stands for previous, 'prev' didn't minify
15367           if (prevEntry) prevEntry.n = nextEntry; //n stands for next, 'next' didn't minify
15368         }
15369       }
15370     }
15371
15372
15373   /**
15374    * @ngdoc method
15375    * @name $cacheFactory#info
15376    *
15377    * @description
15378    * Get information about all the caches that have been created
15379    *
15380    * @returns {Object} - key-value map of `cacheId` to the result of calling `cache#info`
15381    */
15382     cacheFactory.info = function() {
15383       var info = {};
15384       forEach(caches, function(cache, cacheId) {
15385         info[cacheId] = cache.info();
15386       });
15387       return info;
15388     };
15389
15390
15391   /**
15392    * @ngdoc method
15393    * @name $cacheFactory#get
15394    *
15395    * @description
15396    * Get access to a cache object by the `cacheId` used when it was created.
15397    *
15398    * @param {string} cacheId Name or id of a cache to access.
15399    * @returns {object} Cache object identified by the cacheId or undefined if no such cache.
15400    */
15401     cacheFactory.get = function(cacheId) {
15402       return caches[cacheId];
15403     };
15404
15405
15406     return cacheFactory;
15407   };
15408 }
15409
15410 /**
15411  * @ngdoc service
15412  * @name $templateCache
15413  *
15414  * @description
15415  * The first time a template is used, it is loaded in the template cache for quick retrieval. You
15416  * can load templates directly into the cache in a `script` tag, or by consuming the
15417  * `$templateCache` service directly.
15418  *
15419  * Adding via the `script` tag:
15420  *
15421  * ```html
15422  *   <script type="text/ng-template" id="templateId.html">
15423  *     <p>This is the content of the template</p>
15424  *   </script>
15425  * ```
15426  *
15427  * **Note:** the `script` tag containing the template does not need to be included in the `head` of
15428  * the document, but it must be a descendent of the {@link ng.$rootElement $rootElement} (IE,
15429  * element with ng-app attribute), otherwise the template will be ignored.
15430  *
15431  * Adding via the `$templateCache` service:
15432  *
15433  * ```js
15434  * var myApp = angular.module('myApp', []);
15435  * myApp.run(function($templateCache) {
15436  *   $templateCache.put('templateId.html', 'This is the content of the template');
15437  * });
15438  * ```
15439  *
15440  * To retrieve the template later, simply use it in your HTML:
15441  * ```html
15442  * <div ng-include=" 'templateId.html' "></div>
15443  * ```
15444  *
15445  * or get it via Javascript:
15446  * ```js
15447  * $templateCache.get('templateId.html')
15448  * ```
15449  *
15450  * See {@link ng.$cacheFactory $cacheFactory}.
15451  *
15452  */
15453 function $TemplateCacheProvider() {
15454   this.$get = ['$cacheFactory', function($cacheFactory) {
15455     return $cacheFactory('templates');
15456   }];
15457 }
15458
15459 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
15460  *     Any commits to this file should be reviewed with security in mind.  *
15461  *   Changes to this file can potentially create security vulnerabilities. *
15462  *          An approval from 2 Core members with history of modifying      *
15463  *                         this file is required.                          *
15464  *                                                                         *
15465  *  Does the change somehow allow for arbitrary javascript to be executed? *
15466  *    Or allows for someone to change the prototype of built-in objects?   *
15467  *     Or gives undesired access to variables likes document or window?    *
15468  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
15469
15470 /* ! VARIABLE/FUNCTION NAMING CONVENTIONS THAT APPLY TO THIS FILE!
15471  *
15472  * DOM-related variables:
15473  *
15474  * - "node" - DOM Node
15475  * - "element" - DOM Element or Node
15476  * - "$node" or "$element" - jqLite-wrapped node or element
15477  *
15478  *
15479  * Compiler related stuff:
15480  *
15481  * - "linkFn" - linking fn of a single directive
15482  * - "nodeLinkFn" - function that aggregates all linking fns for a particular node
15483  * - "childLinkFn" -  function that aggregates all linking fns for child nodes of a particular node
15484  * - "compositeLinkFn" - function that aggregates all linking fns for a compilation root (nodeList)
15485  */
15486
15487
15488 /**
15489  * @ngdoc service
15490  * @name $compile
15491  * @kind function
15492  *
15493  * @description
15494  * Compiles an HTML string or DOM into a template and produces a template function, which
15495  * can then be used to link {@link ng.$rootScope.Scope `scope`} and the template together.
15496  *
15497  * The compilation is a process of walking the DOM tree and matching DOM elements to
15498  * {@link ng.$compileProvider#directive directives}.
15499  *
15500  * <div class="alert alert-warning">
15501  * **Note:** This document is an in-depth reference of all directive options.
15502  * For a gentle introduction to directives with examples of common use cases,
15503  * see the {@link guide/directive directive guide}.
15504  * </div>
15505  *
15506  * ## Comprehensive Directive API
15507  *
15508  * There are many different options for a directive.
15509  *
15510  * The difference resides in the return value of the factory function.
15511  * You can either return a "Directive Definition Object" (see below) that defines the directive properties,
15512  * or just the `postLink` function (all other properties will have the default values).
15513  *
15514  * <div class="alert alert-success">
15515  * **Best Practice:** It's recommended to use the "directive definition object" form.
15516  * </div>
15517  *
15518  * Here's an example directive declared with a Directive Definition Object:
15519  *
15520  * ```js
15521  *   var myModule = angular.module(...);
15522  *
15523  *   myModule.directive('directiveName', function factory(injectables) {
15524  *     var directiveDefinitionObject = {
15525  *       priority: 0,
15526  *       template: '<div></div>', // or // function(tElement, tAttrs) { ... },
15527  *       // or
15528  *       // templateUrl: 'directive.html', // or // function(tElement, tAttrs) { ... },
15529  *       transclude: false,
15530  *       restrict: 'A',
15531  *       templateNamespace: 'html',
15532  *       scope: false,
15533  *       controller: function($scope, $element, $attrs, $transclude, otherInjectables) { ... },
15534  *       controllerAs: 'stringIdentifier',
15535  *       bindToController: false,
15536  *       require: 'siblingDirectiveName', // or // ['^parentDirectiveName', '?optionalDirectiveName', '?^optionalParent'],
15537  *       compile: function compile(tElement, tAttrs, transclude) {
15538  *         return {
15539  *           pre: function preLink(scope, iElement, iAttrs, controller) { ... },
15540  *           post: function postLink(scope, iElement, iAttrs, controller) { ... }
15541  *         }
15542  *         // or
15543  *         // return function postLink( ... ) { ... }
15544  *       },
15545  *       // or
15546  *       // link: {
15547  *       //  pre: function preLink(scope, iElement, iAttrs, controller) { ... },
15548  *       //  post: function postLink(scope, iElement, iAttrs, controller) { ... }
15549  *       // }
15550  *       // or
15551  *       // link: function postLink( ... ) { ... }
15552  *     };
15553  *     return directiveDefinitionObject;
15554  *   });
15555  * ```
15556  *
15557  * <div class="alert alert-warning">
15558  * **Note:** Any unspecified options will use the default value. You can see the default values below.
15559  * </div>
15560  *
15561  * Therefore the above can be simplified as:
15562  *
15563  * ```js
15564  *   var myModule = angular.module(...);
15565  *
15566  *   myModule.directive('directiveName', function factory(injectables) {
15567  *     var directiveDefinitionObject = {
15568  *       link: function postLink(scope, iElement, iAttrs) { ... }
15569  *     };
15570  *     return directiveDefinitionObject;
15571  *     // or
15572  *     // return function postLink(scope, iElement, iAttrs) { ... }
15573  *   });
15574  * ```
15575  *
15576  *
15577  *
15578  * ### Directive Definition Object
15579  *
15580  * The directive definition object provides instructions to the {@link ng.$compile
15581  * compiler}. The attributes are:
15582  *
15583  * #### `multiElement`
15584  * When this property is set to true, the HTML compiler will collect DOM nodes between
15585  * nodes with the attributes `directive-name-start` and `directive-name-end`, and group them
15586  * together as the directive elements. It is recommended that this feature be used on directives
15587  * which are not strictly behavioural (such as {@link ngClick}), and which
15588  * do not manipulate or replace child nodes (such as {@link ngInclude}).
15589  *
15590  * #### `priority`
15591  * When there are multiple directives defined on a single DOM element, sometimes it
15592  * is necessary to specify the order in which the directives are applied. The `priority` is used
15593  * to sort the directives before their `compile` functions get called. Priority is defined as a
15594  * number. Directives with greater numerical `priority` are compiled first. Pre-link functions
15595  * are also run in priority order, but post-link functions are run in reverse order. The order
15596  * of directives with the same priority is undefined. The default priority is `0`.
15597  *
15598  * #### `terminal`
15599  * If set to true then the current `priority` will be the last set of directives
15600  * which will execute (any directives at the current priority will still execute
15601  * as the order of execution on same `priority` is undefined). Note that expressions
15602  * and other directives used in the directive's template will also be excluded from execution.
15603  *
15604  * #### `scope`
15605  * The scope property can be `true`, an object or a falsy value:
15606  *
15607  * * **falsy:** No scope will be created for the directive. The directive will use its parent's scope.
15608  *
15609  * * **`true`:** A new child scope that prototypically inherits from its parent will be created for
15610  * the directive's element. If multiple directives on the same element request a new scope,
15611  * only one new scope is created. The new scope rule does not apply for the root of the template
15612  * since the root of the template always gets a new scope.
15613  *
15614  * * **`{...}` (an object hash):** A new "isolate" scope is created for the directive's element. The
15615  * 'isolate' scope differs from normal scope in that it does not prototypically inherit from its parent
15616  * scope. This is useful when creating reusable components, which should not accidentally read or modify
15617  * data in the parent scope.
15618  *
15619  * The 'isolate' scope object hash defines a set of local scope properties derived from attributes on the
15620  * directive's element. These local properties are useful for aliasing values for templates. The keys in
15621  * the object hash map to the name of the property on the isolate scope; the values define how the property
15622  * is bound to the parent scope, via matching attributes on the directive's element:
15623  *
15624  * * `@` or `@attr` - bind a local scope property to the value of DOM attribute. The result is
15625  *   always a string since DOM attributes are strings. If no `attr` name is specified  then the
15626  *   attribute name is assumed to be the same as the local name.
15627  *   Given `<widget my-attr="hello {{name}}">` and widget definition
15628  *   of `scope: { localName:'@myAttr' }`, then widget scope property `localName` will reflect
15629  *   the interpolated value of `hello {{name}}`. As the `name` attribute changes so will the
15630  *   `localName` property on the widget scope. The `name` is read from the parent scope (not
15631  *   component scope).
15632  *
15633  * * `=` or `=attr` - set up bi-directional binding between a local scope property and the
15634  *   parent scope property of name defined via the value of the `attr` attribute. If no `attr`
15635  *   name is specified then the attribute name is assumed to be the same as the local name.
15636  *   Given `<widget my-attr="parentModel">` and widget definition of
15637  *   `scope: { localModel:'=myAttr' }`, then widget scope property `localModel` will reflect the
15638  *   value of `parentModel` on the parent scope. Any changes to `parentModel` will be reflected
15639  *   in `localModel` and any changes in `localModel` will reflect in `parentModel`. If the parent
15640  *   scope property doesn't exist, it will throw a NON_ASSIGNABLE_MODEL_EXPRESSION exception. You
15641  *   can avoid this behavior using `=?` or `=?attr` in order to flag the property as optional. If
15642  *   you want to shallow watch for changes (i.e. $watchCollection instead of $watch) you can use
15643  *   `=*` or `=*attr` (`=*?` or `=*?attr` if the property is optional).
15644  *
15645  * * `&` or `&attr` - provides a way to execute an expression in the context of the parent scope.
15646  *   If no `attr` name is specified then the attribute name is assumed to be the same as the
15647  *   local name. Given `<widget my-attr="count = count + value">` and widget definition of
15648  *   `scope: { localFn:'&myAttr' }`, then isolate scope property `localFn` will point to
15649  *   a function wrapper for the `count = count + value` expression. Often it's desirable to
15650  *   pass data from the isolated scope via an expression to the parent scope, this can be
15651  *   done by passing a map of local variable names and values into the expression wrapper fn.
15652  *   For example, if the expression is `increment(amount)` then we can specify the amount value
15653  *   by calling the `localFn` as `localFn({amount: 22})`.
15654  *
15655  * In general it's possible to apply more than one directive to one element, but there might be limitations
15656  * depending on the type of scope required by the directives. The following points will help explain these limitations.
15657  * For simplicity only two directives are taken into account, but it is also applicable for several directives:
15658  *
15659  * * **no scope** + **no scope** => Two directives which don't require their own scope will use their parent's scope
15660  * * **child scope** + **no scope** =>  Both directives will share one single child scope
15661  * * **child scope** + **child scope** =>  Both directives will share one single child scope
15662  * * **isolated scope** + **no scope** =>  The isolated directive will use it's own created isolated scope. The other directive will use
15663  * its parent's scope
15664  * * **isolated scope** + **child scope** =>  **Won't work!** Only one scope can be related to one element. Therefore these directives cannot
15665  * be applied to the same element.
15666  * * **isolated scope** + **isolated scope**  =>  **Won't work!** Only one scope can be related to one element. Therefore these directives
15667  * cannot be applied to the same element.
15668  *
15669  *
15670  * #### `bindToController`
15671  * When an isolate scope is used for a component (see above), and `controllerAs` is used, `bindToController: true` will
15672  * allow a component to have its properties bound to the controller, rather than to scope. When the controller
15673  * is instantiated, the initial values of the isolate scope bindings are already available.
15674  *
15675  * #### `controller`
15676  * Controller constructor function. The controller is instantiated before the
15677  * pre-linking phase and can be accessed by other directives (see
15678  * `require` attribute). This allows the directives to communicate with each other and augment
15679  * each other's behavior. The controller is injectable (and supports bracket notation) with the following locals:
15680  *
15681  * * `$scope` - Current scope associated with the element
15682  * * `$element` - Current element
15683  * * `$attrs` - Current attributes object for the element
15684  * * `$transclude` - A transclude linking function pre-bound to the correct transclusion scope:
15685  *   `function([scope], cloneLinkingFn, futureParentElement)`.
15686  *    * `scope`: optional argument to override the scope.
15687  *    * `cloneLinkingFn`: optional argument to create clones of the original transcluded content.
15688  *    * `futureParentElement`:
15689  *        * defines the parent to which the `cloneLinkingFn` will add the cloned elements.
15690  *        * default: `$element.parent()` resp. `$element` for `transclude:'element'` resp. `transclude:true`.
15691  *        * only needed for transcludes that are allowed to contain non html elements (e.g. SVG elements)
15692  *          and when the `cloneLinkinFn` is passed,
15693  *          as those elements need to created and cloned in a special way when they are defined outside their
15694  *          usual containers (e.g. like `<svg>`).
15695  *        * See also the `directive.templateNamespace` property.
15696  *
15697  *
15698  * #### `require`
15699  * Require another directive and inject its controller as the fourth argument to the linking function. The
15700  * `require` takes a string name (or array of strings) of the directive(s) to pass in. If an array is used, the
15701  * injected argument will be an array in corresponding order. If no such directive can be
15702  * found, or if the directive does not have a controller, then an error is raised (unless no link function
15703  * is specified, in which case error checking is skipped). The name can be prefixed with:
15704  *
15705  * * (no prefix) - Locate the required controller on the current element. Throw an error if not found.
15706  * * `?` - Attempt to locate the required controller or pass `null` to the `link` fn if not found.
15707  * * `^` - Locate the required controller by searching the element and its parents. Throw an error if not found.
15708  * * `^^` - Locate the required controller by searching the element's parents. Throw an error if not found.
15709  * * `?^` - Attempt to locate the required controller by searching the element and its parents or pass
15710  *   `null` to the `link` fn if not found.
15711  * * `?^^` - Attempt to locate the required controller by searching the element's parents, or pass
15712  *   `null` to the `link` fn if not found.
15713  *
15714  *
15715  * #### `controllerAs`
15716  * Identifier name for a reference to the controller in the directive's scope.
15717  * This allows the controller to be referenced from the directive template. This is especially
15718  * useful when a directive is used as component, i.e. with an `isolate` scope. It's also possible
15719  * to use it in a directive without an `isolate` / `new` scope, but you need to be aware that the
15720  * `controllerAs` reference might overwrite a property that already exists on the parent scope.
15721  *
15722  *
15723  * #### `restrict`
15724  * String of subset of `EACM` which restricts the directive to a specific directive
15725  * declaration style. If omitted, the defaults (elements and attributes) are used.
15726  *
15727  * * `E` - Element name (default): `<my-directive></my-directive>`
15728  * * `A` - Attribute (default): `<div my-directive="exp"></div>`
15729  * * `C` - Class: `<div class="my-directive: exp;"></div>`
15730  * * `M` - Comment: `<!-- directive: my-directive exp -->`
15731  *
15732  *
15733  * #### `templateNamespace`
15734  * String representing the document type used by the markup in the template.
15735  * AngularJS needs this information as those elements need to be created and cloned
15736  * in a special way when they are defined outside their usual containers like `<svg>` and `<math>`.
15737  *
15738  * * `html` - All root nodes in the template are HTML. Root nodes may also be
15739  *   top-level elements such as `<svg>` or `<math>`.
15740  * * `svg` - The root nodes in the template are SVG elements (excluding `<math>`).
15741  * * `math` - The root nodes in the template are MathML elements (excluding `<svg>`).
15742  *
15743  * If no `templateNamespace` is specified, then the namespace is considered to be `html`.
15744  *
15745  * #### `template`
15746  * HTML markup that may:
15747  * * Replace the contents of the directive's element (default).
15748  * * Replace the directive's element itself (if `replace` is true - DEPRECATED).
15749  * * Wrap the contents of the directive's element (if `transclude` is true).
15750  *
15751  * Value may be:
15752  *
15753  * * A string. For example `<div red-on-hover>{{delete_str}}</div>`.
15754  * * A function which takes two arguments `tElement` and `tAttrs` (described in the `compile`
15755  *   function api below) and returns a string value.
15756  *
15757  *
15758  * #### `templateUrl`
15759  * This is similar to `template` but the template is loaded from the specified URL, asynchronously.
15760  *
15761  * Because template loading is asynchronous the compiler will suspend compilation of directives on that element
15762  * for later when the template has been resolved.  In the meantime it will continue to compile and link
15763  * sibling and parent elements as though this element had not contained any directives.
15764  *
15765  * The compiler does not suspend the entire compilation to wait for templates to be loaded because this
15766  * would result in the whole app "stalling" until all templates are loaded asynchronously - even in the
15767  * case when only one deeply nested directive has `templateUrl`.
15768  *
15769  * Template loading is asynchronous even if the template has been preloaded into the {@link $templateCache}
15770  *
15771  * You can specify `templateUrl` as a string representing the URL or as a function which takes two
15772  * arguments `tElement` and `tAttrs` (described in the `compile` function api below) and returns
15773  * a string value representing the url.  In either case, the template URL is passed through {@link
15774  * $sce#getTrustedResourceUrl $sce.getTrustedResourceUrl}.
15775  *
15776  *
15777  * #### `replace` ([*DEPRECATED*!], will be removed in next major release - i.e. v2.0)
15778  * specify what the template should replace. Defaults to `false`.
15779  *
15780  * * `true` - the template will replace the directive's element.
15781  * * `false` - the template will replace the contents of the directive's element.
15782  *
15783  * The replacement process migrates all of the attributes / classes from the old element to the new
15784  * one. See the {@link guide/directive#template-expanding-directive
15785  * Directives Guide} for an example.
15786  *
15787  * There are very few scenarios where element replacement is required for the application function,
15788  * the main one being reusable custom components that are used within SVG contexts
15789  * (because SVG doesn't work with custom elements in the DOM tree).
15790  *
15791  * #### `transclude`
15792  * Extract the contents of the element where the directive appears and make it available to the directive.
15793  * The contents are compiled and provided to the directive as a **transclusion function**. See the
15794  * {@link $compile#transclusion Transclusion} section below.
15795  *
15796  * There are two kinds of transclusion depending upon whether you want to transclude just the contents of the
15797  * directive's element or the entire element:
15798  *
15799  * * `true` - transclude the content (i.e. the child nodes) of the directive's element.
15800  * * `'element'` - transclude the whole of the directive's element including any directives on this
15801  *   element that defined at a lower priority than this directive. When used, the `template`
15802  *   property is ignored.
15803  *
15804  *
15805  * #### `compile`
15806  *
15807  * ```js
15808  *   function compile(tElement, tAttrs, transclude) { ... }
15809  * ```
15810  *
15811  * The compile function deals with transforming the template DOM. Since most directives do not do
15812  * template transformation, it is not used often. The compile function takes the following arguments:
15813  *
15814  *   * `tElement` - template element - The element where the directive has been declared. It is
15815  *     safe to do template transformation on the element and child elements only.
15816  *
15817  *   * `tAttrs` - template attributes - Normalized list of attributes declared on this element shared
15818  *     between all directive compile functions.
15819  *
15820  *   * `transclude` -  [*DEPRECATED*!] A transclude linking function: `function(scope, cloneLinkingFn)`
15821  *
15822  * <div class="alert alert-warning">
15823  * **Note:** The template instance and the link instance may be different objects if the template has
15824  * been cloned. For this reason it is **not** safe to do anything other than DOM transformations that
15825  * apply to all cloned DOM nodes within the compile function. Specifically, DOM listener registration
15826  * should be done in a linking function rather than in a compile function.
15827  * </div>
15828
15829  * <div class="alert alert-warning">
15830  * **Note:** The compile function cannot handle directives that recursively use themselves in their
15831  * own templates or compile functions. Compiling these directives results in an infinite loop and a
15832  * stack overflow errors.
15833  *
15834  * This can be avoided by manually using $compile in the postLink function to imperatively compile
15835  * a directive's template instead of relying on automatic template compilation via `template` or
15836  * `templateUrl` declaration or manual compilation inside the compile function.
15837  * </div>
15838  *
15839  * <div class="alert alert-danger">
15840  * **Note:** The `transclude` function that is passed to the compile function is deprecated, as it
15841  *   e.g. does not know about the right outer scope. Please use the transclude function that is passed
15842  *   to the link function instead.
15843  * </div>
15844
15845  * A compile function can have a return value which can be either a function or an object.
15846  *
15847  * * returning a (post-link) function - is equivalent to registering the linking function via the
15848  *   `link` property of the config object when the compile function is empty.
15849  *
15850  * * returning an object with function(s) registered via `pre` and `post` properties - allows you to
15851  *   control when a linking function should be called during the linking phase. See info about
15852  *   pre-linking and post-linking functions below.
15853  *
15854  *
15855  * #### `link`
15856  * This property is used only if the `compile` property is not defined.
15857  *
15858  * ```js
15859  *   function link(scope, iElement, iAttrs, controller, transcludeFn) { ... }
15860  * ```
15861  *
15862  * The link function is responsible for registering DOM listeners as well as updating the DOM. It is
15863  * executed after the template has been cloned. This is where most of the directive logic will be
15864  * put.
15865  *
15866  *   * `scope` - {@link ng.$rootScope.Scope Scope} - The scope to be used by the
15867  *     directive for registering {@link ng.$rootScope.Scope#$watch watches}.
15868  *
15869  *   * `iElement` - instance element - The element where the directive is to be used. It is safe to
15870  *     manipulate the children of the element only in `postLink` function since the children have
15871  *     already been linked.
15872  *
15873  *   * `iAttrs` - instance attributes - Normalized list of attributes declared on this element shared
15874  *     between all directive linking functions.
15875  *
15876  *   * `controller` - the directive's required controller instance(s) - Instances are shared
15877  *     among all directives, which allows the directives to use the controllers as a communication
15878  *     channel. The exact value depends on the directive's `require` property:
15879  *       * no controller(s) required: the directive's own controller, or `undefined` if it doesn't have one
15880  *       * `string`: the controller instance
15881  *       * `array`: array of controller instances
15882  *
15883  *     If a required controller cannot be found, and it is optional, the instance is `null`,
15884  *     otherwise the {@link error:$compile:ctreq Missing Required Controller} error is thrown.
15885  *
15886  *     Note that you can also require the directive's own controller - it will be made available like
15887  *     any other controller.
15888  *
15889  *   * `transcludeFn` - A transclude linking function pre-bound to the correct transclusion scope.
15890  *     This is the same as the `$transclude`
15891  *     parameter of directive controllers, see there for details.
15892  *     `function([scope], cloneLinkingFn, futureParentElement)`.
15893  *
15894  * #### Pre-linking function
15895  *
15896  * Executed before the child elements are linked. Not safe to do DOM transformation since the
15897  * compiler linking function will fail to locate the correct elements for linking.
15898  *
15899  * #### Post-linking function
15900  *
15901  * Executed after the child elements are linked.
15902  *
15903  * Note that child elements that contain `templateUrl` directives will not have been compiled
15904  * and linked since they are waiting for their template to load asynchronously and their own
15905  * compilation and linking has been suspended until that occurs.
15906  *
15907  * It is safe to do DOM transformation in the post-linking function on elements that are not waiting
15908  * for their async templates to be resolved.
15909  *
15910  *
15911  * ### Transclusion
15912  *
15913  * Transclusion is the process of extracting a collection of DOM elements from one part of the DOM and
15914  * copying them to another part of the DOM, while maintaining their connection to the original AngularJS
15915  * scope from where they were taken.
15916  *
15917  * Transclusion is used (often with {@link ngTransclude}) to insert the
15918  * original contents of a directive's element into a specified place in the template of the directive.
15919  * The benefit of transclusion, over simply moving the DOM elements manually, is that the transcluded
15920  * content has access to the properties on the scope from which it was taken, even if the directive
15921  * has isolated scope.
15922  * See the {@link guide/directive#creating-a-directive-that-wraps-other-elements Directives Guide}.
15923  *
15924  * This makes it possible for the widget to have private state for its template, while the transcluded
15925  * content has access to its originating scope.
15926  *
15927  * <div class="alert alert-warning">
15928  * **Note:** When testing an element transclude directive you must not place the directive at the root of the
15929  * DOM fragment that is being compiled. See {@link guide/unit-testing#testing-transclusion-directives
15930  * Testing Transclusion Directives}.
15931  * </div>
15932  *
15933  * #### Transclusion Functions
15934  *
15935  * When a directive requests transclusion, the compiler extracts its contents and provides a **transclusion
15936  * function** to the directive's `link` function and `controller`. This transclusion function is a special
15937  * **linking function** that will return the compiled contents linked to a new transclusion scope.
15938  *
15939  * <div class="alert alert-info">
15940  * If you are just using {@link ngTransclude} then you don't need to worry about this function, since
15941  * ngTransclude will deal with it for us.
15942  * </div>
15943  *
15944  * If you want to manually control the insertion and removal of the transcluded content in your directive
15945  * then you must use this transclude function. When you call a transclude function it returns a a jqLite/JQuery
15946  * object that contains the compiled DOM, which is linked to the correct transclusion scope.
15947  *
15948  * When you call a transclusion function you can pass in a **clone attach function**. This function accepts
15949  * two parameters, `function(clone, scope) { ... }`, where the `clone` is a fresh compiled copy of your transcluded
15950  * content and the `scope` is the newly created transclusion scope, to which the clone is bound.
15951  *
15952  * <div class="alert alert-info">
15953  * **Best Practice**: Always provide a `cloneFn` (clone attach function) when you call a translude function
15954  * since you then get a fresh clone of the original DOM and also have access to the new transclusion scope.
15955  * </div>
15956  *
15957  * It is normal practice to attach your transcluded content (`clone`) to the DOM inside your **clone
15958  * attach function**:
15959  *
15960  * ```js
15961  * var transcludedContent, transclusionScope;
15962  *
15963  * $transclude(function(clone, scope) {
15964  *   element.append(clone);
15965  *   transcludedContent = clone;
15966  *   transclusionScope = scope;
15967  * });
15968  * ```
15969  *
15970  * Later, if you want to remove the transcluded content from your DOM then you should also destroy the
15971  * associated transclusion scope:
15972  *
15973  * ```js
15974  * transcludedContent.remove();
15975  * transclusionScope.$destroy();
15976  * ```
15977  *
15978  * <div class="alert alert-info">
15979  * **Best Practice**: if you intend to add and remove transcluded content manually in your directive
15980  * (by calling the transclude function to get the DOM and calling `element.remove()` to remove it),
15981  * then you are also responsible for calling `$destroy` on the transclusion scope.
15982  * </div>
15983  *
15984  * The built-in DOM manipulation directives, such as {@link ngIf}, {@link ngSwitch} and {@link ngRepeat}
15985  * automatically destroy their transluded clones as necessary so you do not need to worry about this if
15986  * you are simply using {@link ngTransclude} to inject the transclusion into your directive.
15987  *
15988  *
15989  * #### Transclusion Scopes
15990  *
15991  * When you call a transclude function it returns a DOM fragment that is pre-bound to a **transclusion
15992  * scope**. This scope is special, in that it is a child of the directive's scope (and so gets destroyed
15993  * when the directive's scope gets destroyed) but it inherits the properties of the scope from which it
15994  * was taken.
15995  *
15996  * For example consider a directive that uses transclusion and isolated scope. The DOM hierarchy might look
15997  * like this:
15998  *
15999  * ```html
16000  * <div ng-app>
16001  *   <div isolate>
16002  *     <div transclusion>
16003  *     </div>
16004  *   </div>
16005  * </div>
16006  * ```
16007  *
16008  * The `$parent` scope hierarchy will look like this:
16009  *
16010  * ```
16011  * - $rootScope
16012  *   - isolate
16013  *     - transclusion
16014  * ```
16015  *
16016  * but the scopes will inherit prototypically from different scopes to their `$parent`.
16017  *
16018  * ```
16019  * - $rootScope
16020  *   - transclusion
16021  * - isolate
16022  * ```
16023  *
16024  *
16025  * ### Attributes
16026  *
16027  * The {@link ng.$compile.directive.Attributes Attributes} object - passed as a parameter in the
16028  * `link()` or `compile()` functions. It has a variety of uses.
16029  *
16030  * accessing *Normalized attribute names:*
16031  * Directives like 'ngBind' can be expressed in many ways: 'ng:bind', `data-ng-bind`, or 'x-ng-bind'.
16032  * the attributes object allows for normalized access to
16033  *   the attributes.
16034  *
16035  * * *Directive inter-communication:* All directives share the same instance of the attributes
16036  *   object which allows the directives to use the attributes object as inter directive
16037  *   communication.
16038  *
16039  * * *Supports interpolation:* Interpolation attributes are assigned to the attribute object
16040  *   allowing other directives to read the interpolated value.
16041  *
16042  * * *Observing interpolated attributes:* Use `$observe` to observe the value changes of attributes
16043  *   that contain interpolation (e.g. `src="{{bar}}"`). Not only is this very efficient but it's also
16044  *   the only way to easily get the actual value because during the linking phase the interpolation
16045  *   hasn't been evaluated yet and so the value is at this time set to `undefined`.
16046  *
16047  * ```js
16048  * function linkingFn(scope, elm, attrs, ctrl) {
16049  *   // get the attribute value
16050  *   console.log(attrs.ngModel);
16051  *
16052  *   // change the attribute
16053  *   attrs.$set('ngModel', 'new value');
16054  *
16055  *   // observe changes to interpolated attribute
16056  *   attrs.$observe('ngModel', function(value) {
16057  *     console.log('ngModel has changed value to ' + value);
16058  *   });
16059  * }
16060  * ```
16061  *
16062  * ## Example
16063  *
16064  * <div class="alert alert-warning">
16065  * **Note**: Typically directives are registered with `module.directive`. The example below is
16066  * to illustrate how `$compile` works.
16067  * </div>
16068  *
16069  <example module="compileExample">
16070    <file name="index.html">
16071     <script>
16072       angular.module('compileExample', [], function($compileProvider) {
16073         // configure new 'compile' directive by passing a directive
16074         // factory function. The factory function injects the '$compile'
16075         $compileProvider.directive('compile', function($compile) {
16076           // directive factory creates a link function
16077           return function(scope, element, attrs) {
16078             scope.$watch(
16079               function(scope) {
16080                  // watch the 'compile' expression for changes
16081                 return scope.$eval(attrs.compile);
16082               },
16083               function(value) {
16084                 // when the 'compile' expression changes
16085                 // assign it into the current DOM
16086                 element.html(value);
16087
16088                 // compile the new DOM and link it to the current
16089                 // scope.
16090                 // NOTE: we only compile .childNodes so that
16091                 // we don't get into infinite loop compiling ourselves
16092                 $compile(element.contents())(scope);
16093               }
16094             );
16095           };
16096         });
16097       })
16098       .controller('GreeterController', ['$scope', function($scope) {
16099         $scope.name = 'Angular';
16100         $scope.html = 'Hello {{name}}';
16101       }]);
16102     </script>
16103     <div ng-controller="GreeterController">
16104       <input ng-model="name"> <br/>
16105       <textarea ng-model="html"></textarea> <br/>
16106       <div compile="html"></div>
16107     </div>
16108    </file>
16109    <file name="protractor.js" type="protractor">
16110      it('should auto compile', function() {
16111        var textarea = $('textarea');
16112        var output = $('div[compile]');
16113        // The initial state reads 'Hello Angular'.
16114        expect(output.getText()).toBe('Hello Angular');
16115        textarea.clear();
16116        textarea.sendKeys('{{name}}!');
16117        expect(output.getText()).toBe('Angular!');
16118      });
16119    </file>
16120  </example>
16121
16122  *
16123  *
16124  * @param {string|DOMElement} element Element or HTML string to compile into a template function.
16125  * @param {function(angular.Scope, cloneAttachFn=)} transclude function available to directives - DEPRECATED.
16126  *
16127  * <div class="alert alert-danger">
16128  * **Note:** Passing a `transclude` function to the $compile function is deprecated, as it
16129  *   e.g. will not use the right outer scope. Please pass the transclude function as a
16130  *   `parentBoundTranscludeFn` to the link function instead.
16131  * </div>
16132  *
16133  * @param {number} maxPriority only apply directives lower than given priority (Only effects the
16134  *                 root element(s), not their children)
16135  * @returns {function(scope, cloneAttachFn=, options=)} a link function which is used to bind template
16136  * (a DOM element/tree) to a scope. Where:
16137  *
16138  *  * `scope` - A {@link ng.$rootScope.Scope Scope} to bind to.
16139  *  * `cloneAttachFn` - If `cloneAttachFn` is provided, then the link function will clone the
16140  *  `template` and call the `cloneAttachFn` function allowing the caller to attach the
16141  *  cloned elements to the DOM document at the appropriate place. The `cloneAttachFn` is
16142  *  called as: <br/> `cloneAttachFn(clonedElement, scope)` where:
16143  *
16144  *      * `clonedElement` - is a clone of the original `element` passed into the compiler.
16145  *      * `scope` - is the current scope with which the linking function is working with.
16146  *
16147  *  * `options` - An optional object hash with linking options. If `options` is provided, then the following
16148  *  keys may be used to control linking behavior:
16149  *
16150  *      * `parentBoundTranscludeFn` - the transclude function made available to
16151  *        directives; if given, it will be passed through to the link functions of
16152  *        directives found in `element` during compilation.
16153  *      * `transcludeControllers` - an object hash with keys that map controller names
16154  *        to controller instances; if given, it will make the controllers
16155  *        available to directives.
16156  *      * `futureParentElement` - defines the parent to which the `cloneAttachFn` will add
16157  *        the cloned elements; only needed for transcludes that are allowed to contain non html
16158  *        elements (e.g. SVG elements). See also the directive.controller property.
16159  *
16160  * Calling the linking function returns the element of the template. It is either the original
16161  * element passed in, or the clone of the element if the `cloneAttachFn` is provided.
16162  *
16163  * After linking the view is not updated until after a call to $digest which typically is done by
16164  * Angular automatically.
16165  *
16166  * If you need access to the bound view, there are two ways to do it:
16167  *
16168  * - If you are not asking the linking function to clone the template, create the DOM element(s)
16169  *   before you send them to the compiler and keep this reference around.
16170  *   ```js
16171  *     var element = $compile('<p>{{total}}</p>')(scope);
16172  *   ```
16173  *
16174  * - if on the other hand, you need the element to be cloned, the view reference from the original
16175  *   example would not point to the clone, but rather to the original template that was cloned. In
16176  *   this case, you can access the clone via the cloneAttachFn:
16177  *   ```js
16178  *     var templateElement = angular.element('<p>{{total}}</p>'),
16179  *         scope = ....;
16180  *
16181  *     var clonedElement = $compile(templateElement)(scope, function(clonedElement, scope) {
16182  *       //attach the clone to DOM document at the right place
16183  *     });
16184  *
16185  *     //now we have reference to the cloned DOM via `clonedElement`
16186  *   ```
16187  *
16188  *
16189  * For information on how the compiler works, see the
16190  * {@link guide/compiler Angular HTML Compiler} section of the Developer Guide.
16191  */
16192
16193 var $compileMinErr = minErr('$compile');
16194
16195 /**
16196  * @ngdoc provider
16197  * @name $compileProvider
16198  *
16199  * @description
16200  */
16201 $CompileProvider.$inject = ['$provide', '$$sanitizeUriProvider'];
16202 function $CompileProvider($provide, $$sanitizeUriProvider) {
16203   var hasDirectives = {},
16204       Suffix = 'Directive',
16205       COMMENT_DIRECTIVE_REGEXP = /^\s*directive\:\s*([\w\-]+)\s+(.*)$/,
16206       CLASS_DIRECTIVE_REGEXP = /(([\w\-]+)(?:\:([^;]+))?;?)/,
16207       ALL_OR_NOTHING_ATTRS = makeMap('ngSrc,ngSrcset,src,srcset'),
16208       REQUIRE_PREFIX_REGEXP = /^(?:(\^\^?)?(\?)?(\^\^?)?)?/;
16209
16210   // Ref: http://developers.whatwg.org/webappapis.html#event-handler-idl-attributes
16211   // The assumption is that future DOM event attribute names will begin with
16212   // 'on' and be composed of only English letters.
16213   var EVENT_HANDLER_ATTR_REGEXP = /^(on[a-z]+|formaction)$/;
16214
16215   function parseIsolateBindings(scope, directiveName, isController) {
16216     var LOCAL_REGEXP = /^\s*([@&]|=(\*?))(\??)\s*(\w*)\s*$/;
16217
16218     var bindings = {};
16219
16220     forEach(scope, function(definition, scopeName) {
16221       var match = definition.match(LOCAL_REGEXP);
16222
16223       if (!match) {
16224         throw $compileMinErr('iscp',
16225             "Invalid {3} for directive '{0}'." +
16226             " Definition: {... {1}: '{2}' ...}",
16227             directiveName, scopeName, definition,
16228             (isController ? "controller bindings definition" :
16229             "isolate scope definition"));
16230       }
16231
16232       bindings[scopeName] = {
16233         mode: match[1][0],
16234         collection: match[2] === '*',
16235         optional: match[3] === '?',
16236         attrName: match[4] || scopeName
16237       };
16238     });
16239
16240     return bindings;
16241   }
16242
16243   function parseDirectiveBindings(directive, directiveName) {
16244     var bindings = {
16245       isolateScope: null,
16246       bindToController: null
16247     };
16248     if (isObject(directive.scope)) {
16249       if (directive.bindToController === true) {
16250         bindings.bindToController = parseIsolateBindings(directive.scope,
16251                                                          directiveName, true);
16252         bindings.isolateScope = {};
16253       } else {
16254         bindings.isolateScope = parseIsolateBindings(directive.scope,
16255                                                      directiveName, false);
16256       }
16257     }
16258     if (isObject(directive.bindToController)) {
16259       bindings.bindToController =
16260           parseIsolateBindings(directive.bindToController, directiveName, true);
16261     }
16262     if (isObject(bindings.bindToController)) {
16263       var controller = directive.controller;
16264       var controllerAs = directive.controllerAs;
16265       if (!controller) {
16266         // There is no controller, there may or may not be a controllerAs property
16267         throw $compileMinErr('noctrl',
16268               "Cannot bind to controller without directive '{0}'s controller.",
16269               directiveName);
16270       } else if (!identifierForController(controller, controllerAs)) {
16271         // There is a controller, but no identifier or controllerAs property
16272         throw $compileMinErr('noident',
16273               "Cannot bind to controller without identifier for directive '{0}'.",
16274               directiveName);
16275       }
16276     }
16277     return bindings;
16278   }
16279
16280   function assertValidDirectiveName(name) {
16281     var letter = name.charAt(0);
16282     if (!letter || letter !== lowercase(letter)) {
16283       throw $compileMinErr('baddir', "Directive name '{0}' is invalid. The first character must be a lowercase letter", name);
16284     }
16285     if (name !== name.trim()) {
16286       throw $compileMinErr('baddir',
16287             "Directive name '{0}' is invalid. The name should not contain leading or trailing whitespaces",
16288             name);
16289     }
16290   }
16291
16292   /**
16293    * @ngdoc method
16294    * @name $compileProvider#directive
16295    * @kind function
16296    *
16297    * @description
16298    * Register a new directive with the compiler.
16299    *
16300    * @param {string|Object} name Name of the directive in camel-case (i.e. <code>ngBind</code> which
16301    *    will match as <code>ng-bind</code>), or an object map of directives where the keys are the
16302    *    names and the values are the factories.
16303    * @param {Function|Array} directiveFactory An injectable directive factory function. See
16304    *    {@link guide/directive} for more info.
16305    * @returns {ng.$compileProvider} Self for chaining.
16306    */
16307    this.directive = function registerDirective(name, directiveFactory) {
16308     assertNotHasOwnProperty(name, 'directive');
16309     if (isString(name)) {
16310       assertValidDirectiveName(name);
16311       assertArg(directiveFactory, 'directiveFactory');
16312       if (!hasDirectives.hasOwnProperty(name)) {
16313         hasDirectives[name] = [];
16314         $provide.factory(name + Suffix, ['$injector', '$exceptionHandler',
16315           function($injector, $exceptionHandler) {
16316             var directives = [];
16317             forEach(hasDirectives[name], function(directiveFactory, index) {
16318               try {
16319                 var directive = $injector.invoke(directiveFactory);
16320                 if (isFunction(directive)) {
16321                   directive = { compile: valueFn(directive) };
16322                 } else if (!directive.compile && directive.link) {
16323                   directive.compile = valueFn(directive.link);
16324                 }
16325                 directive.priority = directive.priority || 0;
16326                 directive.index = index;
16327                 directive.name = directive.name || name;
16328                 directive.require = directive.require || (directive.controller && directive.name);
16329                 directive.restrict = directive.restrict || 'EA';
16330                 var bindings = directive.$$bindings =
16331                     parseDirectiveBindings(directive, directive.name);
16332                 if (isObject(bindings.isolateScope)) {
16333                   directive.$$isolateBindings = bindings.isolateScope;
16334                 }
16335                 directive.$$moduleName = directiveFactory.$$moduleName;
16336                 directives.push(directive);
16337               } catch (e) {
16338                 $exceptionHandler(e);
16339               }
16340             });
16341             return directives;
16342           }]);
16343       }
16344       hasDirectives[name].push(directiveFactory);
16345     } else {
16346       forEach(name, reverseParams(registerDirective));
16347     }
16348     return this;
16349   };
16350
16351
16352   /**
16353    * @ngdoc method
16354    * @name $compileProvider#aHrefSanitizationWhitelist
16355    * @kind function
16356    *
16357    * @description
16358    * Retrieves or overrides the default regular expression that is used for whitelisting of safe
16359    * urls during a[href] sanitization.
16360    *
16361    * The sanitization is a security measure aimed at preventing XSS attacks via html links.
16362    *
16363    * Any url about to be assigned to a[href] via data-binding is first normalized and turned into
16364    * an absolute url. Afterwards, the url is matched against the `aHrefSanitizationWhitelist`
16365    * regular expression. If a match is found, the original url is written into the dom. Otherwise,
16366    * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM.
16367    *
16368    * @param {RegExp=} regexp New regexp to whitelist urls with.
16369    * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
16370    *    chaining otherwise.
16371    */
16372   this.aHrefSanitizationWhitelist = function(regexp) {
16373     if (isDefined(regexp)) {
16374       $$sanitizeUriProvider.aHrefSanitizationWhitelist(regexp);
16375       return this;
16376     } else {
16377       return $$sanitizeUriProvider.aHrefSanitizationWhitelist();
16378     }
16379   };
16380
16381
16382   /**
16383    * @ngdoc method
16384    * @name $compileProvider#imgSrcSanitizationWhitelist
16385    * @kind function
16386    *
16387    * @description
16388    * Retrieves or overrides the default regular expression that is used for whitelisting of safe
16389    * urls during img[src] sanitization.
16390    *
16391    * The sanitization is a security measure aimed at prevent XSS attacks via html links.
16392    *
16393    * Any url about to be assigned to img[src] via data-binding is first normalized and turned into
16394    * an absolute url. Afterwards, the url is matched against the `imgSrcSanitizationWhitelist`
16395    * regular expression. If a match is found, the original url is written into the dom. Otherwise,
16396    * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM.
16397    *
16398    * @param {RegExp=} regexp New regexp to whitelist urls with.
16399    * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
16400    *    chaining otherwise.
16401    */
16402   this.imgSrcSanitizationWhitelist = function(regexp) {
16403     if (isDefined(regexp)) {
16404       $$sanitizeUriProvider.imgSrcSanitizationWhitelist(regexp);
16405       return this;
16406     } else {
16407       return $$sanitizeUriProvider.imgSrcSanitizationWhitelist();
16408     }
16409   };
16410
16411   /**
16412    * @ngdoc method
16413    * @name  $compileProvider#debugInfoEnabled
16414    *
16415    * @param {boolean=} enabled update the debugInfoEnabled state if provided, otherwise just return the
16416    * current debugInfoEnabled state
16417    * @returns {*} current value if used as getter or itself (chaining) if used as setter
16418    *
16419    * @kind function
16420    *
16421    * @description
16422    * Call this method to enable/disable various debug runtime information in the compiler such as adding
16423    * binding information and a reference to the current scope on to DOM elements.
16424    * If enabled, the compiler will add the following to DOM elements that have been bound to the scope
16425    * * `ng-binding` CSS class
16426    * * `$binding` data property containing an array of the binding expressions
16427    *
16428    * You may want to disable this in production for a significant performance boost. See
16429    * {@link guide/production#disabling-debug-data Disabling Debug Data} for more.
16430    *
16431    * The default value is true.
16432    */
16433   var debugInfoEnabled = true;
16434   this.debugInfoEnabled = function(enabled) {
16435     if (isDefined(enabled)) {
16436       debugInfoEnabled = enabled;
16437       return this;
16438     }
16439     return debugInfoEnabled;
16440   };
16441
16442   this.$get = [
16443             '$injector', '$interpolate', '$exceptionHandler', '$templateRequest', '$parse',
16444             '$controller', '$rootScope', '$document', '$sce', '$animate', '$$sanitizeUri',
16445     function($injector,   $interpolate,   $exceptionHandler,   $templateRequest,   $parse,
16446              $controller,   $rootScope,   $document,   $sce,   $animate,   $$sanitizeUri) {
16447
16448     var Attributes = function(element, attributesToCopy) {
16449       if (attributesToCopy) {
16450         var keys = Object.keys(attributesToCopy);
16451         var i, l, key;
16452
16453         for (i = 0, l = keys.length; i < l; i++) {
16454           key = keys[i];
16455           this[key] = attributesToCopy[key];
16456         }
16457       } else {
16458         this.$attr = {};
16459       }
16460
16461       this.$$element = element;
16462     };
16463
16464     Attributes.prototype = {
16465       /**
16466        * @ngdoc method
16467        * @name $compile.directive.Attributes#$normalize
16468        * @kind function
16469        *
16470        * @description
16471        * Converts an attribute name (e.g. dash/colon/underscore-delimited string, optionally prefixed with `x-` or
16472        * `data-`) to its normalized, camelCase form.
16473        *
16474        * Also there is special case for Moz prefix starting with upper case letter.
16475        *
16476        * For further information check out the guide on {@link guide/directive#matching-directives Matching Directives}
16477        *
16478        * @param {string} name Name to normalize
16479        */
16480       $normalize: directiveNormalize,
16481
16482
16483       /**
16484        * @ngdoc method
16485        * @name $compile.directive.Attributes#$addClass
16486        * @kind function
16487        *
16488        * @description
16489        * Adds the CSS class value specified by the classVal parameter to the element. If animations
16490        * are enabled then an animation will be triggered for the class addition.
16491        *
16492        * @param {string} classVal The className value that will be added to the element
16493        */
16494       $addClass: function(classVal) {
16495         if (classVal && classVal.length > 0) {
16496           $animate.addClass(this.$$element, classVal);
16497         }
16498       },
16499
16500       /**
16501        * @ngdoc method
16502        * @name $compile.directive.Attributes#$removeClass
16503        * @kind function
16504        *
16505        * @description
16506        * Removes the CSS class value specified by the classVal parameter from the element. If
16507        * animations are enabled then an animation will be triggered for the class removal.
16508        *
16509        * @param {string} classVal The className value that will be removed from the element
16510        */
16511       $removeClass: function(classVal) {
16512         if (classVal && classVal.length > 0) {
16513           $animate.removeClass(this.$$element, classVal);
16514         }
16515       },
16516
16517       /**
16518        * @ngdoc method
16519        * @name $compile.directive.Attributes#$updateClass
16520        * @kind function
16521        *
16522        * @description
16523        * Adds and removes the appropriate CSS class values to the element based on the difference
16524        * between the new and old CSS class values (specified as newClasses and oldClasses).
16525        *
16526        * @param {string} newClasses The current CSS className value
16527        * @param {string} oldClasses The former CSS className value
16528        */
16529       $updateClass: function(newClasses, oldClasses) {
16530         var toAdd = tokenDifference(newClasses, oldClasses);
16531         if (toAdd && toAdd.length) {
16532           $animate.addClass(this.$$element, toAdd);
16533         }
16534
16535         var toRemove = tokenDifference(oldClasses, newClasses);
16536         if (toRemove && toRemove.length) {
16537           $animate.removeClass(this.$$element, toRemove);
16538         }
16539       },
16540
16541       /**
16542        * Set a normalized attribute on the element in a way such that all directives
16543        * can share the attribute. This function properly handles boolean attributes.
16544        * @param {string} key Normalized key. (ie ngAttribute)
16545        * @param {string|boolean} value The value to set. If `null` attribute will be deleted.
16546        * @param {boolean=} writeAttr If false, does not write the value to DOM element attribute.
16547        *     Defaults to true.
16548        * @param {string=} attrName Optional none normalized name. Defaults to key.
16549        */
16550       $set: function(key, value, writeAttr, attrName) {
16551         // TODO: decide whether or not to throw an error if "class"
16552         //is set through this function since it may cause $updateClass to
16553         //become unstable.
16554
16555         var node = this.$$element[0],
16556             booleanKey = getBooleanAttrName(node, key),
16557             aliasedKey = getAliasedAttrName(key),
16558             observer = key,
16559             nodeName;
16560
16561         if (booleanKey) {
16562           this.$$element.prop(key, value);
16563           attrName = booleanKey;
16564         } else if (aliasedKey) {
16565           this[aliasedKey] = value;
16566           observer = aliasedKey;
16567         }
16568
16569         this[key] = value;
16570
16571         // translate normalized key to actual key
16572         if (attrName) {
16573           this.$attr[key] = attrName;
16574         } else {
16575           attrName = this.$attr[key];
16576           if (!attrName) {
16577             this.$attr[key] = attrName = snake_case(key, '-');
16578           }
16579         }
16580
16581         nodeName = nodeName_(this.$$element);
16582
16583         if ((nodeName === 'a' && key === 'href') ||
16584             (nodeName === 'img' && key === 'src')) {
16585           // sanitize a[href] and img[src] values
16586           this[key] = value = $$sanitizeUri(value, key === 'src');
16587         } else if (nodeName === 'img' && key === 'srcset') {
16588           // sanitize img[srcset] values
16589           var result = "";
16590
16591           // first check if there are spaces because it's not the same pattern
16592           var trimmedSrcset = trim(value);
16593           //                (   999x   ,|   999w   ,|   ,|,   )
16594           var srcPattern = /(\s+\d+x\s*,|\s+\d+w\s*,|\s+,|,\s+)/;
16595           var pattern = /\s/.test(trimmedSrcset) ? srcPattern : /(,)/;
16596
16597           // split srcset into tuple of uri and descriptor except for the last item
16598           var rawUris = trimmedSrcset.split(pattern);
16599
16600           // for each tuples
16601           var nbrUrisWith2parts = Math.floor(rawUris.length / 2);
16602           for (var i = 0; i < nbrUrisWith2parts; i++) {
16603             var innerIdx = i * 2;
16604             // sanitize the uri
16605             result += $$sanitizeUri(trim(rawUris[innerIdx]), true);
16606             // add the descriptor
16607             result += (" " + trim(rawUris[innerIdx + 1]));
16608           }
16609
16610           // split the last item into uri and descriptor
16611           var lastTuple = trim(rawUris[i * 2]).split(/\s/);
16612
16613           // sanitize the last uri
16614           result += $$sanitizeUri(trim(lastTuple[0]), true);
16615
16616           // and add the last descriptor if any
16617           if (lastTuple.length === 2) {
16618             result += (" " + trim(lastTuple[1]));
16619           }
16620           this[key] = value = result;
16621         }
16622
16623         if (writeAttr !== false) {
16624           if (value === null || isUndefined(value)) {
16625             this.$$element.removeAttr(attrName);
16626           } else {
16627             this.$$element.attr(attrName, value);
16628           }
16629         }
16630
16631         // fire observers
16632         var $$observers = this.$$observers;
16633         $$observers && forEach($$observers[observer], function(fn) {
16634           try {
16635             fn(value);
16636           } catch (e) {
16637             $exceptionHandler(e);
16638           }
16639         });
16640       },
16641
16642
16643       /**
16644        * @ngdoc method
16645        * @name $compile.directive.Attributes#$observe
16646        * @kind function
16647        *
16648        * @description
16649        * Observes an interpolated attribute.
16650        *
16651        * The observer function will be invoked once during the next `$digest` following
16652        * compilation. The observer is then invoked whenever the interpolated value
16653        * changes.
16654        *
16655        * @param {string} key Normalized key. (ie ngAttribute) .
16656        * @param {function(interpolatedValue)} fn Function that will be called whenever
16657                 the interpolated value of the attribute changes.
16658        *        See the {@link guide/directive#text-and-attribute-bindings Directives} guide for more info.
16659        * @returns {function()} Returns a deregistration function for this observer.
16660        */
16661       $observe: function(key, fn) {
16662         var attrs = this,
16663             $$observers = (attrs.$$observers || (attrs.$$observers = createMap())),
16664             listeners = ($$observers[key] || ($$observers[key] = []));
16665
16666         listeners.push(fn);
16667         $rootScope.$evalAsync(function() {
16668           if (!listeners.$$inter && attrs.hasOwnProperty(key) && !isUndefined(attrs[key])) {
16669             // no one registered attribute interpolation function, so lets call it manually
16670             fn(attrs[key]);
16671           }
16672         });
16673
16674         return function() {
16675           arrayRemove(listeners, fn);
16676         };
16677       }
16678     };
16679
16680
16681     function safeAddClass($element, className) {
16682       try {
16683         $element.addClass(className);
16684       } catch (e) {
16685         // ignore, since it means that we are trying to set class on
16686         // SVG element, where class name is read-only.
16687       }
16688     }
16689
16690
16691     var startSymbol = $interpolate.startSymbol(),
16692         endSymbol = $interpolate.endSymbol(),
16693         denormalizeTemplate = (startSymbol == '{{' || endSymbol  == '}}')
16694             ? identity
16695             : function denormalizeTemplate(template) {
16696               return template.replace(/\{\{/g, startSymbol).replace(/}}/g, endSymbol);
16697         },
16698         NG_ATTR_BINDING = /^ngAttr[A-Z]/;
16699     var MULTI_ELEMENT_DIR_RE = /^(.+)Start$/;
16700
16701     compile.$$addBindingInfo = debugInfoEnabled ? function $$addBindingInfo($element, binding) {
16702       var bindings = $element.data('$binding') || [];
16703
16704       if (isArray(binding)) {
16705         bindings = bindings.concat(binding);
16706       } else {
16707         bindings.push(binding);
16708       }
16709
16710       $element.data('$binding', bindings);
16711     } : noop;
16712
16713     compile.$$addBindingClass = debugInfoEnabled ? function $$addBindingClass($element) {
16714       safeAddClass($element, 'ng-binding');
16715     } : noop;
16716
16717     compile.$$addScopeInfo = debugInfoEnabled ? function $$addScopeInfo($element, scope, isolated, noTemplate) {
16718       var dataName = isolated ? (noTemplate ? '$isolateScopeNoTemplate' : '$isolateScope') : '$scope';
16719       $element.data(dataName, scope);
16720     } : noop;
16721
16722     compile.$$addScopeClass = debugInfoEnabled ? function $$addScopeClass($element, isolated) {
16723       safeAddClass($element, isolated ? 'ng-isolate-scope' : 'ng-scope');
16724     } : noop;
16725
16726     return compile;
16727
16728     //================================
16729
16730     function compile($compileNodes, transcludeFn, maxPriority, ignoreDirective,
16731                         previousCompileContext) {
16732       if (!($compileNodes instanceof jqLite)) {
16733         // jquery always rewraps, whereas we need to preserve the original selector so that we can
16734         // modify it.
16735         $compileNodes = jqLite($compileNodes);
16736       }
16737       // We can not compile top level text elements since text nodes can be merged and we will
16738       // not be able to attach scope data to them, so we will wrap them in <span>
16739       forEach($compileNodes, function(node, index) {
16740         if (node.nodeType == NODE_TYPE_TEXT && node.nodeValue.match(/\S+/) /* non-empty */ ) {
16741           $compileNodes[index] = jqLite(node).wrap('<span></span>').parent()[0];
16742         }
16743       });
16744       var compositeLinkFn =
16745               compileNodes($compileNodes, transcludeFn, $compileNodes,
16746                            maxPriority, ignoreDirective, previousCompileContext);
16747       compile.$$addScopeClass($compileNodes);
16748       var namespace = null;
16749       return function publicLinkFn(scope, cloneConnectFn, options) {
16750         assertArg(scope, 'scope');
16751
16752         if (previousCompileContext && previousCompileContext.needsNewScope) {
16753           // A parent directive did a replace and a directive on this element asked
16754           // for transclusion, which caused us to lose a layer of element on which
16755           // we could hold the new transclusion scope, so we will create it manually
16756           // here.
16757           scope = scope.$parent.$new();
16758         }
16759
16760         options = options || {};
16761         var parentBoundTranscludeFn = options.parentBoundTranscludeFn,
16762           transcludeControllers = options.transcludeControllers,
16763           futureParentElement = options.futureParentElement;
16764
16765         // When `parentBoundTranscludeFn` is passed, it is a
16766         // `controllersBoundTransclude` function (it was previously passed
16767         // as `transclude` to directive.link) so we must unwrap it to get
16768         // its `boundTranscludeFn`
16769         if (parentBoundTranscludeFn && parentBoundTranscludeFn.$$boundTransclude) {
16770           parentBoundTranscludeFn = parentBoundTranscludeFn.$$boundTransclude;
16771         }
16772
16773         if (!namespace) {
16774           namespace = detectNamespaceForChildElements(futureParentElement);
16775         }
16776         var $linkNode;
16777         if (namespace !== 'html') {
16778           // When using a directive with replace:true and templateUrl the $compileNodes
16779           // (or a child element inside of them)
16780           // might change, so we need to recreate the namespace adapted compileNodes
16781           // for call to the link function.
16782           // Note: This will already clone the nodes...
16783           $linkNode = jqLite(
16784             wrapTemplate(namespace, jqLite('<div>').append($compileNodes).html())
16785           );
16786         } else if (cloneConnectFn) {
16787           // important!!: we must call our jqLite.clone() since the jQuery one is trying to be smart
16788           // and sometimes changes the structure of the DOM.
16789           $linkNode = JQLitePrototype.clone.call($compileNodes);
16790         } else {
16791           $linkNode = $compileNodes;
16792         }
16793
16794         if (transcludeControllers) {
16795           for (var controllerName in transcludeControllers) {
16796             $linkNode.data('$' + controllerName + 'Controller', transcludeControllers[controllerName].instance);
16797           }
16798         }
16799
16800         compile.$$addScopeInfo($linkNode, scope);
16801
16802         if (cloneConnectFn) cloneConnectFn($linkNode, scope);
16803         if (compositeLinkFn) compositeLinkFn(scope, $linkNode, $linkNode, parentBoundTranscludeFn);
16804         return $linkNode;
16805       };
16806     }
16807
16808     function detectNamespaceForChildElements(parentElement) {
16809       // TODO: Make this detect MathML as well...
16810       var node = parentElement && parentElement[0];
16811       if (!node) {
16812         return 'html';
16813       } else {
16814         return nodeName_(node) !== 'foreignobject' && node.toString().match(/SVG/) ? 'svg' : 'html';
16815       }
16816     }
16817
16818     /**
16819      * Compile function matches each node in nodeList against the directives. Once all directives
16820      * for a particular node are collected their compile functions are executed. The compile
16821      * functions return values - the linking functions - are combined into a composite linking
16822      * function, which is the a linking function for the node.
16823      *
16824      * @param {NodeList} nodeList an array of nodes or NodeList to compile
16825      * @param {function(angular.Scope, cloneAttachFn=)} transcludeFn A linking function, where the
16826      *        scope argument is auto-generated to the new child of the transcluded parent scope.
16827      * @param {DOMElement=} $rootElement If the nodeList is the root of the compilation tree then
16828      *        the rootElement must be set the jqLite collection of the compile root. This is
16829      *        needed so that the jqLite collection items can be replaced with widgets.
16830      * @param {number=} maxPriority Max directive priority.
16831      * @returns {Function} A composite linking function of all of the matched directives or null.
16832      */
16833     function compileNodes(nodeList, transcludeFn, $rootElement, maxPriority, ignoreDirective,
16834                             previousCompileContext) {
16835       var linkFns = [],
16836           attrs, directives, nodeLinkFn, childNodes, childLinkFn, linkFnFound, nodeLinkFnFound;
16837
16838       for (var i = 0; i < nodeList.length; i++) {
16839         attrs = new Attributes();
16840
16841         // we must always refer to nodeList[i] since the nodes can be replaced underneath us.
16842         directives = collectDirectives(nodeList[i], [], attrs, i === 0 ? maxPriority : undefined,
16843                                         ignoreDirective);
16844
16845         nodeLinkFn = (directives.length)
16846             ? applyDirectivesToNode(directives, nodeList[i], attrs, transcludeFn, $rootElement,
16847                                       null, [], [], previousCompileContext)
16848             : null;
16849
16850         if (nodeLinkFn && nodeLinkFn.scope) {
16851           compile.$$addScopeClass(attrs.$$element);
16852         }
16853
16854         childLinkFn = (nodeLinkFn && nodeLinkFn.terminal ||
16855                       !(childNodes = nodeList[i].childNodes) ||
16856                       !childNodes.length)
16857             ? null
16858             : compileNodes(childNodes,
16859                  nodeLinkFn ? (
16860                   (nodeLinkFn.transcludeOnThisElement || !nodeLinkFn.templateOnThisElement)
16861                      && nodeLinkFn.transclude) : transcludeFn);
16862
16863         if (nodeLinkFn || childLinkFn) {
16864           linkFns.push(i, nodeLinkFn, childLinkFn);
16865           linkFnFound = true;
16866           nodeLinkFnFound = nodeLinkFnFound || nodeLinkFn;
16867         }
16868
16869         //use the previous context only for the first element in the virtual group
16870         previousCompileContext = null;
16871       }
16872
16873       // return a linking function if we have found anything, null otherwise
16874       return linkFnFound ? compositeLinkFn : null;
16875
16876       function compositeLinkFn(scope, nodeList, $rootElement, parentBoundTranscludeFn) {
16877         var nodeLinkFn, childLinkFn, node, childScope, i, ii, idx, childBoundTranscludeFn;
16878         var stableNodeList;
16879
16880
16881         if (nodeLinkFnFound) {
16882           // copy nodeList so that if a nodeLinkFn removes or adds an element at this DOM level our
16883           // offsets don't get screwed up
16884           var nodeListLength = nodeList.length;
16885           stableNodeList = new Array(nodeListLength);
16886
16887           // create a sparse array by only copying the elements which have a linkFn
16888           for (i = 0; i < linkFns.length; i+=3) {
16889             idx = linkFns[i];
16890             stableNodeList[idx] = nodeList[idx];
16891           }
16892         } else {
16893           stableNodeList = nodeList;
16894         }
16895
16896         for (i = 0, ii = linkFns.length; i < ii;) {
16897           node = stableNodeList[linkFns[i++]];
16898           nodeLinkFn = linkFns[i++];
16899           childLinkFn = linkFns[i++];
16900
16901           if (nodeLinkFn) {
16902             if (nodeLinkFn.scope) {
16903               childScope = scope.$new();
16904               compile.$$addScopeInfo(jqLite(node), childScope);
16905             } else {
16906               childScope = scope;
16907             }
16908
16909             if (nodeLinkFn.transcludeOnThisElement) {
16910               childBoundTranscludeFn = createBoundTranscludeFn(
16911                   scope, nodeLinkFn.transclude, parentBoundTranscludeFn);
16912
16913             } else if (!nodeLinkFn.templateOnThisElement && parentBoundTranscludeFn) {
16914               childBoundTranscludeFn = parentBoundTranscludeFn;
16915
16916             } else if (!parentBoundTranscludeFn && transcludeFn) {
16917               childBoundTranscludeFn = createBoundTranscludeFn(scope, transcludeFn);
16918
16919             } else {
16920               childBoundTranscludeFn = null;
16921             }
16922
16923             nodeLinkFn(childLinkFn, childScope, node, $rootElement, childBoundTranscludeFn);
16924
16925           } else if (childLinkFn) {
16926             childLinkFn(scope, node.childNodes, undefined, parentBoundTranscludeFn);
16927           }
16928         }
16929       }
16930     }
16931
16932     function createBoundTranscludeFn(scope, transcludeFn, previousBoundTranscludeFn) {
16933
16934       var boundTranscludeFn = function(transcludedScope, cloneFn, controllers, futureParentElement, containingScope) {
16935
16936         if (!transcludedScope) {
16937           transcludedScope = scope.$new(false, containingScope);
16938           transcludedScope.$$transcluded = true;
16939         }
16940
16941         return transcludeFn(transcludedScope, cloneFn, {
16942           parentBoundTranscludeFn: previousBoundTranscludeFn,
16943           transcludeControllers: controllers,
16944           futureParentElement: futureParentElement
16945         });
16946       };
16947
16948       return boundTranscludeFn;
16949     }
16950
16951     /**
16952      * Looks for directives on the given node and adds them to the directive collection which is
16953      * sorted.
16954      *
16955      * @param node Node to search.
16956      * @param directives An array to which the directives are added to. This array is sorted before
16957      *        the function returns.
16958      * @param attrs The shared attrs object which is used to populate the normalized attributes.
16959      * @param {number=} maxPriority Max directive priority.
16960      */
16961     function collectDirectives(node, directives, attrs, maxPriority, ignoreDirective) {
16962       var nodeType = node.nodeType,
16963           attrsMap = attrs.$attr,
16964           match,
16965           className;
16966
16967       switch (nodeType) {
16968         case NODE_TYPE_ELEMENT: /* Element */
16969           // use the node name: <directive>
16970           addDirective(directives,
16971               directiveNormalize(nodeName_(node)), 'E', maxPriority, ignoreDirective);
16972
16973           // iterate over the attributes
16974           for (var attr, name, nName, ngAttrName, value, isNgAttr, nAttrs = node.attributes,
16975                    j = 0, jj = nAttrs && nAttrs.length; j < jj; j++) {
16976             var attrStartName = false;
16977             var attrEndName = false;
16978
16979             attr = nAttrs[j];
16980             name = attr.name;
16981             value = trim(attr.value);
16982
16983             // support ngAttr attribute binding
16984             ngAttrName = directiveNormalize(name);
16985             if (isNgAttr = NG_ATTR_BINDING.test(ngAttrName)) {
16986               name = name.replace(PREFIX_REGEXP, '')
16987                 .substr(8).replace(/_(.)/g, function(match, letter) {
16988                   return letter.toUpperCase();
16989                 });
16990             }
16991
16992             var multiElementMatch = ngAttrName.match(MULTI_ELEMENT_DIR_RE);
16993             if (multiElementMatch && directiveIsMultiElement(multiElementMatch[1])) {
16994               attrStartName = name;
16995               attrEndName = name.substr(0, name.length - 5) + 'end';
16996               name = name.substr(0, name.length - 6);
16997             }
16998
16999             nName = directiveNormalize(name.toLowerCase());
17000             attrsMap[nName] = name;
17001             if (isNgAttr || !attrs.hasOwnProperty(nName)) {
17002                 attrs[nName] = value;
17003                 if (getBooleanAttrName(node, nName)) {
17004                   attrs[nName] = true; // presence means true
17005                 }
17006             }
17007             addAttrInterpolateDirective(node, directives, value, nName, isNgAttr);
17008             addDirective(directives, nName, 'A', maxPriority, ignoreDirective, attrStartName,
17009                           attrEndName);
17010           }
17011
17012           // use class as directive
17013           className = node.className;
17014           if (isObject(className)) {
17015               // Maybe SVGAnimatedString
17016               className = className.animVal;
17017           }
17018           if (isString(className) && className !== '') {
17019             while (match = CLASS_DIRECTIVE_REGEXP.exec(className)) {
17020               nName = directiveNormalize(match[2]);
17021               if (addDirective(directives, nName, 'C', maxPriority, ignoreDirective)) {
17022                 attrs[nName] = trim(match[3]);
17023               }
17024               className = className.substr(match.index + match[0].length);
17025             }
17026           }
17027           break;
17028         case NODE_TYPE_TEXT: /* Text Node */
17029           if (msie === 11) {
17030             // Workaround for #11781
17031             while (node.parentNode && node.nextSibling && node.nextSibling.nodeType === NODE_TYPE_TEXT) {
17032               node.nodeValue = node.nodeValue + node.nextSibling.nodeValue;
17033               node.parentNode.removeChild(node.nextSibling);
17034             }
17035           }
17036           addTextInterpolateDirective(directives, node.nodeValue);
17037           break;
17038         case NODE_TYPE_COMMENT: /* Comment */
17039           try {
17040             match = COMMENT_DIRECTIVE_REGEXP.exec(node.nodeValue);
17041             if (match) {
17042               nName = directiveNormalize(match[1]);
17043               if (addDirective(directives, nName, 'M', maxPriority, ignoreDirective)) {
17044                 attrs[nName] = trim(match[2]);
17045               }
17046             }
17047           } catch (e) {
17048             // turns out that under some circumstances IE9 throws errors when one attempts to read
17049             // comment's node value.
17050             // Just ignore it and continue. (Can't seem to reproduce in test case.)
17051           }
17052           break;
17053       }
17054
17055       directives.sort(byPriority);
17056       return directives;
17057     }
17058
17059     /**
17060      * Given a node with an directive-start it collects all of the siblings until it finds
17061      * directive-end.
17062      * @param node
17063      * @param attrStart
17064      * @param attrEnd
17065      * @returns {*}
17066      */
17067     function groupScan(node, attrStart, attrEnd) {
17068       var nodes = [];
17069       var depth = 0;
17070       if (attrStart && node.hasAttribute && node.hasAttribute(attrStart)) {
17071         do {
17072           if (!node) {
17073             throw $compileMinErr('uterdir',
17074                       "Unterminated attribute, found '{0}' but no matching '{1}' found.",
17075                       attrStart, attrEnd);
17076           }
17077           if (node.nodeType == NODE_TYPE_ELEMENT) {
17078             if (node.hasAttribute(attrStart)) depth++;
17079             if (node.hasAttribute(attrEnd)) depth--;
17080           }
17081           nodes.push(node);
17082           node = node.nextSibling;
17083         } while (depth > 0);
17084       } else {
17085         nodes.push(node);
17086       }
17087
17088       return jqLite(nodes);
17089     }
17090
17091     /**
17092      * Wrapper for linking function which converts normal linking function into a grouped
17093      * linking function.
17094      * @param linkFn
17095      * @param attrStart
17096      * @param attrEnd
17097      * @returns {Function}
17098      */
17099     function groupElementsLinkFnWrapper(linkFn, attrStart, attrEnd) {
17100       return function(scope, element, attrs, controllers, transcludeFn) {
17101         element = groupScan(element[0], attrStart, attrEnd);
17102         return linkFn(scope, element, attrs, controllers, transcludeFn);
17103       };
17104     }
17105
17106     /**
17107      * Once the directives have been collected, their compile functions are executed. This method
17108      * is responsible for inlining directive templates as well as terminating the application
17109      * of the directives if the terminal directive has been reached.
17110      *
17111      * @param {Array} directives Array of collected directives to execute their compile function.
17112      *        this needs to be pre-sorted by priority order.
17113      * @param {Node} compileNode The raw DOM node to apply the compile functions to
17114      * @param {Object} templateAttrs The shared attribute function
17115      * @param {function(angular.Scope, cloneAttachFn=)} transcludeFn A linking function, where the
17116      *                                                  scope argument is auto-generated to the new
17117      *                                                  child of the transcluded parent scope.
17118      * @param {JQLite} jqCollection If we are working on the root of the compile tree then this
17119      *                              argument has the root jqLite array so that we can replace nodes
17120      *                              on it.
17121      * @param {Object=} originalReplaceDirective An optional directive that will be ignored when
17122      *                                           compiling the transclusion.
17123      * @param {Array.<Function>} preLinkFns
17124      * @param {Array.<Function>} postLinkFns
17125      * @param {Object} previousCompileContext Context used for previous compilation of the current
17126      *                                        node
17127      * @returns {Function} linkFn
17128      */
17129     function applyDirectivesToNode(directives, compileNode, templateAttrs, transcludeFn,
17130                                    jqCollection, originalReplaceDirective, preLinkFns, postLinkFns,
17131                                    previousCompileContext) {
17132       previousCompileContext = previousCompileContext || {};
17133
17134       var terminalPriority = -Number.MAX_VALUE,
17135           newScopeDirective = previousCompileContext.newScopeDirective,
17136           controllerDirectives = previousCompileContext.controllerDirectives,
17137           newIsolateScopeDirective = previousCompileContext.newIsolateScopeDirective,
17138           templateDirective = previousCompileContext.templateDirective,
17139           nonTlbTranscludeDirective = previousCompileContext.nonTlbTranscludeDirective,
17140           hasTranscludeDirective = false,
17141           hasTemplate = false,
17142           hasElementTranscludeDirective = previousCompileContext.hasElementTranscludeDirective,
17143           $compileNode = templateAttrs.$$element = jqLite(compileNode),
17144           directive,
17145           directiveName,
17146           $template,
17147           replaceDirective = originalReplaceDirective,
17148           childTranscludeFn = transcludeFn,
17149           linkFn,
17150           directiveValue;
17151
17152       // executes all directives on the current element
17153       for (var i = 0, ii = directives.length; i < ii; i++) {
17154         directive = directives[i];
17155         var attrStart = directive.$$start;
17156         var attrEnd = directive.$$end;
17157
17158         // collect multiblock sections
17159         if (attrStart) {
17160           $compileNode = groupScan(compileNode, attrStart, attrEnd);
17161         }
17162         $template = undefined;
17163
17164         if (terminalPriority > directive.priority) {
17165           break; // prevent further processing of directives
17166         }
17167
17168         if (directiveValue = directive.scope) {
17169
17170           // skip the check for directives with async templates, we'll check the derived sync
17171           // directive when the template arrives
17172           if (!directive.templateUrl) {
17173             if (isObject(directiveValue)) {
17174               // This directive is trying to add an isolated scope.
17175               // Check that there is no scope of any kind already
17176               assertNoDuplicate('new/isolated scope', newIsolateScopeDirective || newScopeDirective,
17177                                 directive, $compileNode);
17178               newIsolateScopeDirective = directive;
17179             } else {
17180               // This directive is trying to add a child scope.
17181               // Check that there is no isolated scope already
17182               assertNoDuplicate('new/isolated scope', newIsolateScopeDirective, directive,
17183                                 $compileNode);
17184             }
17185           }
17186
17187           newScopeDirective = newScopeDirective || directive;
17188         }
17189
17190         directiveName = directive.name;
17191
17192         if (!directive.templateUrl && directive.controller) {
17193           directiveValue = directive.controller;
17194           controllerDirectives = controllerDirectives || createMap();
17195           assertNoDuplicate("'" + directiveName + "' controller",
17196               controllerDirectives[directiveName], directive, $compileNode);
17197           controllerDirectives[directiveName] = directive;
17198         }
17199
17200         if (directiveValue = directive.transclude) {
17201           hasTranscludeDirective = true;
17202
17203           // Special case ngIf and ngRepeat so that we don't complain about duplicate transclusion.
17204           // This option should only be used by directives that know how to safely handle element transclusion,
17205           // where the transcluded nodes are added or replaced after linking.
17206           if (!directive.$$tlb) {
17207             assertNoDuplicate('transclusion', nonTlbTranscludeDirective, directive, $compileNode);
17208             nonTlbTranscludeDirective = directive;
17209           }
17210
17211           if (directiveValue == 'element') {
17212             hasElementTranscludeDirective = true;
17213             terminalPriority = directive.priority;
17214             $template = $compileNode;
17215             $compileNode = templateAttrs.$$element =
17216                 jqLite(document.createComment(' ' + directiveName + ': ' +
17217                                               templateAttrs[directiveName] + ' '));
17218             compileNode = $compileNode[0];
17219             replaceWith(jqCollection, sliceArgs($template), compileNode);
17220
17221             childTranscludeFn = compile($template, transcludeFn, terminalPriority,
17222                                         replaceDirective && replaceDirective.name, {
17223                                           // Don't pass in:
17224                                           // - controllerDirectives - otherwise we'll create duplicates controllers
17225                                           // - newIsolateScopeDirective or templateDirective - combining templates with
17226                                           //   element transclusion doesn't make sense.
17227                                           //
17228                                           // We need only nonTlbTranscludeDirective so that we prevent putting transclusion
17229                                           // on the same element more than once.
17230                                           nonTlbTranscludeDirective: nonTlbTranscludeDirective
17231                                         });
17232           } else {
17233             $template = jqLite(jqLiteClone(compileNode)).contents();
17234             $compileNode.empty(); // clear contents
17235             childTranscludeFn = compile($template, transcludeFn, undefined,
17236                 undefined, { needsNewScope: directive.$$isolateScope || directive.$$newScope});
17237           }
17238         }
17239
17240         if (directive.template) {
17241           hasTemplate = true;
17242           assertNoDuplicate('template', templateDirective, directive, $compileNode);
17243           templateDirective = directive;
17244
17245           directiveValue = (isFunction(directive.template))
17246               ? directive.template($compileNode, templateAttrs)
17247               : directive.template;
17248
17249           directiveValue = denormalizeTemplate(directiveValue);
17250
17251           if (directive.replace) {
17252             replaceDirective = directive;
17253             if (jqLiteIsTextNode(directiveValue)) {
17254               $template = [];
17255             } else {
17256               $template = removeComments(wrapTemplate(directive.templateNamespace, trim(directiveValue)));
17257             }
17258             compileNode = $template[0];
17259
17260             if ($template.length != 1 || compileNode.nodeType !== NODE_TYPE_ELEMENT) {
17261               throw $compileMinErr('tplrt',
17262                   "Template for directive '{0}' must have exactly one root element. {1}",
17263                   directiveName, '');
17264             }
17265
17266             replaceWith(jqCollection, $compileNode, compileNode);
17267
17268             var newTemplateAttrs = {$attr: {}};
17269
17270             // combine directives from the original node and from the template:
17271             // - take the array of directives for this element
17272             // - split it into two parts, those that already applied (processed) and those that weren't (unprocessed)
17273             // - collect directives from the template and sort them by priority
17274             // - combine directives as: processed + template + unprocessed
17275             var templateDirectives = collectDirectives(compileNode, [], newTemplateAttrs);
17276             var unprocessedDirectives = directives.splice(i + 1, directives.length - (i + 1));
17277
17278             if (newIsolateScopeDirective || newScopeDirective) {
17279               // The original directive caused the current element to be replaced but this element
17280               // also needs to have a new scope, so we need to tell the template directives
17281               // that they would need to get their scope from further up, if they require transclusion
17282               markDirectiveScope(templateDirectives, newIsolateScopeDirective, newScopeDirective);
17283             }
17284             directives = directives.concat(templateDirectives).concat(unprocessedDirectives);
17285             mergeTemplateAttributes(templateAttrs, newTemplateAttrs);
17286
17287             ii = directives.length;
17288           } else {
17289             $compileNode.html(directiveValue);
17290           }
17291         }
17292
17293         if (directive.templateUrl) {
17294           hasTemplate = true;
17295           assertNoDuplicate('template', templateDirective, directive, $compileNode);
17296           templateDirective = directive;
17297
17298           if (directive.replace) {
17299             replaceDirective = directive;
17300           }
17301
17302           nodeLinkFn = compileTemplateUrl(directives.splice(i, directives.length - i), $compileNode,
17303               templateAttrs, jqCollection, hasTranscludeDirective && childTranscludeFn, preLinkFns, postLinkFns, {
17304                 controllerDirectives: controllerDirectives,
17305                 newScopeDirective: (newScopeDirective !== directive) && newScopeDirective,
17306                 newIsolateScopeDirective: newIsolateScopeDirective,
17307                 templateDirective: templateDirective,
17308                 nonTlbTranscludeDirective: nonTlbTranscludeDirective
17309               });
17310           ii = directives.length;
17311         } else if (directive.compile) {
17312           try {
17313             linkFn = directive.compile($compileNode, templateAttrs, childTranscludeFn);
17314             if (isFunction(linkFn)) {
17315               addLinkFns(null, linkFn, attrStart, attrEnd);
17316             } else if (linkFn) {
17317               addLinkFns(linkFn.pre, linkFn.post, attrStart, attrEnd);
17318             }
17319           } catch (e) {
17320             $exceptionHandler(e, startingTag($compileNode));
17321           }
17322         }
17323
17324         if (directive.terminal) {
17325           nodeLinkFn.terminal = true;
17326           terminalPriority = Math.max(terminalPriority, directive.priority);
17327         }
17328
17329       }
17330
17331       nodeLinkFn.scope = newScopeDirective && newScopeDirective.scope === true;
17332       nodeLinkFn.transcludeOnThisElement = hasTranscludeDirective;
17333       nodeLinkFn.templateOnThisElement = hasTemplate;
17334       nodeLinkFn.transclude = childTranscludeFn;
17335
17336       previousCompileContext.hasElementTranscludeDirective = hasElementTranscludeDirective;
17337
17338       // might be normal or delayed nodeLinkFn depending on if templateUrl is present
17339       return nodeLinkFn;
17340
17341       ////////////////////
17342
17343       function addLinkFns(pre, post, attrStart, attrEnd) {
17344         if (pre) {
17345           if (attrStart) pre = groupElementsLinkFnWrapper(pre, attrStart, attrEnd);
17346           pre.require = directive.require;
17347           pre.directiveName = directiveName;
17348           if (newIsolateScopeDirective === directive || directive.$$isolateScope) {
17349             pre = cloneAndAnnotateFn(pre, {isolateScope: true});
17350           }
17351           preLinkFns.push(pre);
17352         }
17353         if (post) {
17354           if (attrStart) post = groupElementsLinkFnWrapper(post, attrStart, attrEnd);
17355           post.require = directive.require;
17356           post.directiveName = directiveName;
17357           if (newIsolateScopeDirective === directive || directive.$$isolateScope) {
17358             post = cloneAndAnnotateFn(post, {isolateScope: true});
17359           }
17360           postLinkFns.push(post);
17361         }
17362       }
17363
17364
17365       function getControllers(directiveName, require, $element, elementControllers) {
17366         var value;
17367
17368         if (isString(require)) {
17369           var match = require.match(REQUIRE_PREFIX_REGEXP);
17370           var name = require.substring(match[0].length);
17371           var inheritType = match[1] || match[3];
17372           var optional = match[2] === '?';
17373
17374           //If only parents then start at the parent element
17375           if (inheritType === '^^') {
17376             $element = $element.parent();
17377           //Otherwise attempt getting the controller from elementControllers in case
17378           //the element is transcluded (and has no data) and to avoid .data if possible
17379           } else {
17380             value = elementControllers && elementControllers[name];
17381             value = value && value.instance;
17382           }
17383
17384           if (!value) {
17385             var dataName = '$' + name + 'Controller';
17386             value = inheritType ? $element.inheritedData(dataName) : $element.data(dataName);
17387           }
17388
17389           if (!value && !optional) {
17390             throw $compileMinErr('ctreq',
17391                 "Controller '{0}', required by directive '{1}', can't be found!",
17392                 name, directiveName);
17393           }
17394         } else if (isArray(require)) {
17395           value = [];
17396           for (var i = 0, ii = require.length; i < ii; i++) {
17397             value[i] = getControllers(directiveName, require[i], $element, elementControllers);
17398           }
17399         }
17400
17401         return value || null;
17402       }
17403
17404       function setupControllers($element, attrs, transcludeFn, controllerDirectives, isolateScope, scope) {
17405         var elementControllers = createMap();
17406         for (var controllerKey in controllerDirectives) {
17407           var directive = controllerDirectives[controllerKey];
17408           var locals = {
17409             $scope: directive === newIsolateScopeDirective || directive.$$isolateScope ? isolateScope : scope,
17410             $element: $element,
17411             $attrs: attrs,
17412             $transclude: transcludeFn
17413           };
17414
17415           var controller = directive.controller;
17416           if (controller == '@') {
17417             controller = attrs[directive.name];
17418           }
17419
17420           var controllerInstance = $controller(controller, locals, true, directive.controllerAs);
17421
17422           // For directives with element transclusion the element is a comment,
17423           // but jQuery .data doesn't support attaching data to comment nodes as it's hard to
17424           // clean up (http://bugs.jquery.com/ticket/8335).
17425           // Instead, we save the controllers for the element in a local hash and attach to .data
17426           // later, once we have the actual element.
17427           elementControllers[directive.name] = controllerInstance;
17428           if (!hasElementTranscludeDirective) {
17429             $element.data('$' + directive.name + 'Controller', controllerInstance.instance);
17430           }
17431         }
17432         return elementControllers;
17433       }
17434
17435       function nodeLinkFn(childLinkFn, scope, linkNode, $rootElement, boundTranscludeFn) {
17436         var linkFn, isolateScope, controllerScope, elementControllers, transcludeFn, $element,
17437             attrs, removeScopeBindingWatches, removeControllerBindingWatches;
17438
17439         if (compileNode === linkNode) {
17440           attrs = templateAttrs;
17441           $element = templateAttrs.$$element;
17442         } else {
17443           $element = jqLite(linkNode);
17444           attrs = new Attributes($element, templateAttrs);
17445         }
17446
17447         controllerScope = scope;
17448         if (newIsolateScopeDirective) {
17449           isolateScope = scope.$new(true);
17450         } else if (newScopeDirective) {
17451           controllerScope = scope.$parent;
17452         }
17453
17454         if (boundTranscludeFn) {
17455           // track `boundTranscludeFn` so it can be unwrapped if `transcludeFn`
17456           // is later passed as `parentBoundTranscludeFn` to `publicLinkFn`
17457           transcludeFn = controllersBoundTransclude;
17458           transcludeFn.$$boundTransclude = boundTranscludeFn;
17459         }
17460
17461         if (controllerDirectives) {
17462           elementControllers = setupControllers($element, attrs, transcludeFn, controllerDirectives, isolateScope, scope);
17463         }
17464
17465         if (newIsolateScopeDirective) {
17466           // Initialize isolate scope bindings for new isolate scope directive.
17467           compile.$$addScopeInfo($element, isolateScope, true, !(templateDirective && (templateDirective === newIsolateScopeDirective ||
17468               templateDirective === newIsolateScopeDirective.$$originalDirective)));
17469           compile.$$addScopeClass($element, true);
17470           isolateScope.$$isolateBindings =
17471               newIsolateScopeDirective.$$isolateBindings;
17472           removeScopeBindingWatches = initializeDirectiveBindings(scope, attrs, isolateScope,
17473                                         isolateScope.$$isolateBindings,
17474                                         newIsolateScopeDirective);
17475           if (removeScopeBindingWatches) {
17476             isolateScope.$on('$destroy', removeScopeBindingWatches);
17477           }
17478         }
17479
17480         // Initialize bindToController bindings
17481         for (var name in elementControllers) {
17482           var controllerDirective = controllerDirectives[name];
17483           var controller = elementControllers[name];
17484           var bindings = controllerDirective.$$bindings.bindToController;
17485
17486           if (controller.identifier && bindings) {
17487             removeControllerBindingWatches =
17488               initializeDirectiveBindings(controllerScope, attrs, controller.instance, bindings, controllerDirective);
17489           }
17490
17491           var controllerResult = controller();
17492           if (controllerResult !== controller.instance) {
17493             // If the controller constructor has a return value, overwrite the instance
17494             // from setupControllers
17495             controller.instance = controllerResult;
17496             $element.data('$' + controllerDirective.name + 'Controller', controllerResult);
17497             removeControllerBindingWatches && removeControllerBindingWatches();
17498             removeControllerBindingWatches =
17499               initializeDirectiveBindings(controllerScope, attrs, controller.instance, bindings, controllerDirective);
17500           }
17501         }
17502
17503         // PRELINKING
17504         for (i = 0, ii = preLinkFns.length; i < ii; i++) {
17505           linkFn = preLinkFns[i];
17506           invokeLinkFn(linkFn,
17507               linkFn.isolateScope ? isolateScope : scope,
17508               $element,
17509               attrs,
17510               linkFn.require && getControllers(linkFn.directiveName, linkFn.require, $element, elementControllers),
17511               transcludeFn
17512           );
17513         }
17514
17515         // RECURSION
17516         // We only pass the isolate scope, if the isolate directive has a template,
17517         // otherwise the child elements do not belong to the isolate directive.
17518         var scopeToChild = scope;
17519         if (newIsolateScopeDirective && (newIsolateScopeDirective.template || newIsolateScopeDirective.templateUrl === null)) {
17520           scopeToChild = isolateScope;
17521         }
17522         childLinkFn && childLinkFn(scopeToChild, linkNode.childNodes, undefined, boundTranscludeFn);
17523
17524         // POSTLINKING
17525         for (i = postLinkFns.length - 1; i >= 0; i--) {
17526           linkFn = postLinkFns[i];
17527           invokeLinkFn(linkFn,
17528               linkFn.isolateScope ? isolateScope : scope,
17529               $element,
17530               attrs,
17531               linkFn.require && getControllers(linkFn.directiveName, linkFn.require, $element, elementControllers),
17532               transcludeFn
17533           );
17534         }
17535
17536         // This is the function that is injected as `$transclude`.
17537         // Note: all arguments are optional!
17538         function controllersBoundTransclude(scope, cloneAttachFn, futureParentElement) {
17539           var transcludeControllers;
17540
17541           // No scope passed in:
17542           if (!isScope(scope)) {
17543             futureParentElement = cloneAttachFn;
17544             cloneAttachFn = scope;
17545             scope = undefined;
17546           }
17547
17548           if (hasElementTranscludeDirective) {
17549             transcludeControllers = elementControllers;
17550           }
17551           if (!futureParentElement) {
17552             futureParentElement = hasElementTranscludeDirective ? $element.parent() : $element;
17553           }
17554           return boundTranscludeFn(scope, cloneAttachFn, transcludeControllers, futureParentElement, scopeToChild);
17555         }
17556       }
17557     }
17558
17559     // Depending upon the context in which a directive finds itself it might need to have a new isolated
17560     // or child scope created. For instance:
17561     // * if the directive has been pulled into a template because another directive with a higher priority
17562     // asked for element transclusion
17563     // * if the directive itself asks for transclusion but it is at the root of a template and the original
17564     // element was replaced. See https://github.com/angular/angular.js/issues/12936
17565     function markDirectiveScope(directives, isolateScope, newScope) {
17566       for (var j = 0, jj = directives.length; j < jj; j++) {
17567         directives[j] = inherit(directives[j], {$$isolateScope: isolateScope, $$newScope: newScope});
17568       }
17569     }
17570
17571     /**
17572      * looks up the directive and decorates it with exception handling and proper parameters. We
17573      * call this the boundDirective.
17574      *
17575      * @param {string} name name of the directive to look up.
17576      * @param {string} location The directive must be found in specific format.
17577      *   String containing any of theses characters:
17578      *
17579      *   * `E`: element name
17580      *   * `A': attribute
17581      *   * `C`: class
17582      *   * `M`: comment
17583      * @returns {boolean} true if directive was added.
17584      */
17585     function addDirective(tDirectives, name, location, maxPriority, ignoreDirective, startAttrName,
17586                           endAttrName) {
17587       if (name === ignoreDirective) return null;
17588       var match = null;
17589       if (hasDirectives.hasOwnProperty(name)) {
17590         for (var directive, directives = $injector.get(name + Suffix),
17591             i = 0, ii = directives.length; i < ii; i++) {
17592           try {
17593             directive = directives[i];
17594             if ((isUndefined(maxPriority) || maxPriority > directive.priority) &&
17595                  directive.restrict.indexOf(location) != -1) {
17596               if (startAttrName) {
17597                 directive = inherit(directive, {$$start: startAttrName, $$end: endAttrName});
17598               }
17599               tDirectives.push(directive);
17600               match = directive;
17601             }
17602           } catch (e) { $exceptionHandler(e); }
17603         }
17604       }
17605       return match;
17606     }
17607
17608
17609     /**
17610      * looks up the directive and returns true if it is a multi-element directive,
17611      * and therefore requires DOM nodes between -start and -end markers to be grouped
17612      * together.
17613      *
17614      * @param {string} name name of the directive to look up.
17615      * @returns true if directive was registered as multi-element.
17616      */
17617     function directiveIsMultiElement(name) {
17618       if (hasDirectives.hasOwnProperty(name)) {
17619         for (var directive, directives = $injector.get(name + Suffix),
17620             i = 0, ii = directives.length; i < ii; i++) {
17621           directive = directives[i];
17622           if (directive.multiElement) {
17623             return true;
17624           }
17625         }
17626       }
17627       return false;
17628     }
17629
17630     /**
17631      * When the element is replaced with HTML template then the new attributes
17632      * on the template need to be merged with the existing attributes in the DOM.
17633      * The desired effect is to have both of the attributes present.
17634      *
17635      * @param {object} dst destination attributes (original DOM)
17636      * @param {object} src source attributes (from the directive template)
17637      */
17638     function mergeTemplateAttributes(dst, src) {
17639       var srcAttr = src.$attr,
17640           dstAttr = dst.$attr,
17641           $element = dst.$$element;
17642
17643       // reapply the old attributes to the new element
17644       forEach(dst, function(value, key) {
17645         if (key.charAt(0) != '$') {
17646           if (src[key] && src[key] !== value) {
17647             value += (key === 'style' ? ';' : ' ') + src[key];
17648           }
17649           dst.$set(key, value, true, srcAttr[key]);
17650         }
17651       });
17652
17653       // copy the new attributes on the old attrs object
17654       forEach(src, function(value, key) {
17655         if (key == 'class') {
17656           safeAddClass($element, value);
17657           dst['class'] = (dst['class'] ? dst['class'] + ' ' : '') + value;
17658         } else if (key == 'style') {
17659           $element.attr('style', $element.attr('style') + ';' + value);
17660           dst['style'] = (dst['style'] ? dst['style'] + ';' : '') + value;
17661           // `dst` will never contain hasOwnProperty as DOM parser won't let it.
17662           // You will get an "InvalidCharacterError: DOM Exception 5" error if you
17663           // have an attribute like "has-own-property" or "data-has-own-property", etc.
17664         } else if (key.charAt(0) != '$' && !dst.hasOwnProperty(key)) {
17665           dst[key] = value;
17666           dstAttr[key] = srcAttr[key];
17667         }
17668       });
17669     }
17670
17671
17672     function compileTemplateUrl(directives, $compileNode, tAttrs,
17673         $rootElement, childTranscludeFn, preLinkFns, postLinkFns, previousCompileContext) {
17674       var linkQueue = [],
17675           afterTemplateNodeLinkFn,
17676           afterTemplateChildLinkFn,
17677           beforeTemplateCompileNode = $compileNode[0],
17678           origAsyncDirective = directives.shift(),
17679           derivedSyncDirective = inherit(origAsyncDirective, {
17680             templateUrl: null, transclude: null, replace: null, $$originalDirective: origAsyncDirective
17681           }),
17682           templateUrl = (isFunction(origAsyncDirective.templateUrl))
17683               ? origAsyncDirective.templateUrl($compileNode, tAttrs)
17684               : origAsyncDirective.templateUrl,
17685           templateNamespace = origAsyncDirective.templateNamespace;
17686
17687       $compileNode.empty();
17688
17689       $templateRequest(templateUrl)
17690         .then(function(content) {
17691           var compileNode, tempTemplateAttrs, $template, childBoundTranscludeFn;
17692
17693           content = denormalizeTemplate(content);
17694
17695           if (origAsyncDirective.replace) {
17696             if (jqLiteIsTextNode(content)) {
17697               $template = [];
17698             } else {
17699               $template = removeComments(wrapTemplate(templateNamespace, trim(content)));
17700             }
17701             compileNode = $template[0];
17702
17703             if ($template.length != 1 || compileNode.nodeType !== NODE_TYPE_ELEMENT) {
17704               throw $compileMinErr('tplrt',
17705                   "Template for directive '{0}' must have exactly one root element. {1}",
17706                   origAsyncDirective.name, templateUrl);
17707             }
17708
17709             tempTemplateAttrs = {$attr: {}};
17710             replaceWith($rootElement, $compileNode, compileNode);
17711             var templateDirectives = collectDirectives(compileNode, [], tempTemplateAttrs);
17712
17713             if (isObject(origAsyncDirective.scope)) {
17714               // the original directive that caused the template to be loaded async required
17715               // an isolate scope
17716               markDirectiveScope(templateDirectives, true);
17717             }
17718             directives = templateDirectives.concat(directives);
17719             mergeTemplateAttributes(tAttrs, tempTemplateAttrs);
17720           } else {
17721             compileNode = beforeTemplateCompileNode;
17722             $compileNode.html(content);
17723           }
17724
17725           directives.unshift(derivedSyncDirective);
17726
17727           afterTemplateNodeLinkFn = applyDirectivesToNode(directives, compileNode, tAttrs,
17728               childTranscludeFn, $compileNode, origAsyncDirective, preLinkFns, postLinkFns,
17729               previousCompileContext);
17730           forEach($rootElement, function(node, i) {
17731             if (node == compileNode) {
17732               $rootElement[i] = $compileNode[0];
17733             }
17734           });
17735           afterTemplateChildLinkFn = compileNodes($compileNode[0].childNodes, childTranscludeFn);
17736
17737           while (linkQueue.length) {
17738             var scope = linkQueue.shift(),
17739                 beforeTemplateLinkNode = linkQueue.shift(),
17740                 linkRootElement = linkQueue.shift(),
17741                 boundTranscludeFn = linkQueue.shift(),
17742                 linkNode = $compileNode[0];
17743
17744             if (scope.$$destroyed) continue;
17745
17746             if (beforeTemplateLinkNode !== beforeTemplateCompileNode) {
17747               var oldClasses = beforeTemplateLinkNode.className;
17748
17749               if (!(previousCompileContext.hasElementTranscludeDirective &&
17750                   origAsyncDirective.replace)) {
17751                 // it was cloned therefore we have to clone as well.
17752                 linkNode = jqLiteClone(compileNode);
17753               }
17754               replaceWith(linkRootElement, jqLite(beforeTemplateLinkNode), linkNode);
17755
17756               // Copy in CSS classes from original node
17757               safeAddClass(jqLite(linkNode), oldClasses);
17758             }
17759             if (afterTemplateNodeLinkFn.transcludeOnThisElement) {
17760               childBoundTranscludeFn = createBoundTranscludeFn(scope, afterTemplateNodeLinkFn.transclude, boundTranscludeFn);
17761             } else {
17762               childBoundTranscludeFn = boundTranscludeFn;
17763             }
17764             afterTemplateNodeLinkFn(afterTemplateChildLinkFn, scope, linkNode, $rootElement,
17765               childBoundTranscludeFn);
17766           }
17767           linkQueue = null;
17768         });
17769
17770       return function delayedNodeLinkFn(ignoreChildLinkFn, scope, node, rootElement, boundTranscludeFn) {
17771         var childBoundTranscludeFn = boundTranscludeFn;
17772         if (scope.$$destroyed) return;
17773         if (linkQueue) {
17774           linkQueue.push(scope,
17775                          node,
17776                          rootElement,
17777                          childBoundTranscludeFn);
17778         } else {
17779           if (afterTemplateNodeLinkFn.transcludeOnThisElement) {
17780             childBoundTranscludeFn = createBoundTranscludeFn(scope, afterTemplateNodeLinkFn.transclude, boundTranscludeFn);
17781           }
17782           afterTemplateNodeLinkFn(afterTemplateChildLinkFn, scope, node, rootElement, childBoundTranscludeFn);
17783         }
17784       };
17785     }
17786
17787
17788     /**
17789      * Sorting function for bound directives.
17790      */
17791     function byPriority(a, b) {
17792       var diff = b.priority - a.priority;
17793       if (diff !== 0) return diff;
17794       if (a.name !== b.name) return (a.name < b.name) ? -1 : 1;
17795       return a.index - b.index;
17796     }
17797
17798     function assertNoDuplicate(what, previousDirective, directive, element) {
17799
17800       function wrapModuleNameIfDefined(moduleName) {
17801         return moduleName ?
17802           (' (module: ' + moduleName + ')') :
17803           '';
17804       }
17805
17806       if (previousDirective) {
17807         throw $compileMinErr('multidir', 'Multiple directives [{0}{1}, {2}{3}] asking for {4} on: {5}',
17808             previousDirective.name, wrapModuleNameIfDefined(previousDirective.$$moduleName),
17809             directive.name, wrapModuleNameIfDefined(directive.$$moduleName), what, startingTag(element));
17810       }
17811     }
17812
17813
17814     function addTextInterpolateDirective(directives, text) {
17815       var interpolateFn = $interpolate(text, true);
17816       if (interpolateFn) {
17817         directives.push({
17818           priority: 0,
17819           compile: function textInterpolateCompileFn(templateNode) {
17820             var templateNodeParent = templateNode.parent(),
17821                 hasCompileParent = !!templateNodeParent.length;
17822
17823             // When transcluding a template that has bindings in the root
17824             // we don't have a parent and thus need to add the class during linking fn.
17825             if (hasCompileParent) compile.$$addBindingClass(templateNodeParent);
17826
17827             return function textInterpolateLinkFn(scope, node) {
17828               var parent = node.parent();
17829               if (!hasCompileParent) compile.$$addBindingClass(parent);
17830               compile.$$addBindingInfo(parent, interpolateFn.expressions);
17831               scope.$watch(interpolateFn, function interpolateFnWatchAction(value) {
17832                 node[0].nodeValue = value;
17833               });
17834             };
17835           }
17836         });
17837       }
17838     }
17839
17840
17841     function wrapTemplate(type, template) {
17842       type = lowercase(type || 'html');
17843       switch (type) {
17844       case 'svg':
17845       case 'math':
17846         var wrapper = document.createElement('div');
17847         wrapper.innerHTML = '<' + type + '>' + template + '</' + type + '>';
17848         return wrapper.childNodes[0].childNodes;
17849       default:
17850         return template;
17851       }
17852     }
17853
17854
17855     function getTrustedContext(node, attrNormalizedName) {
17856       if (attrNormalizedName == "srcdoc") {
17857         return $sce.HTML;
17858       }
17859       var tag = nodeName_(node);
17860       // maction[xlink:href] can source SVG.  It's not limited to <maction>.
17861       if (attrNormalizedName == "xlinkHref" ||
17862           (tag == "form" && attrNormalizedName == "action") ||
17863           (tag != "img" && (attrNormalizedName == "src" ||
17864                             attrNormalizedName == "ngSrc"))) {
17865         return $sce.RESOURCE_URL;
17866       }
17867     }
17868
17869
17870     function addAttrInterpolateDirective(node, directives, value, name, allOrNothing) {
17871       var trustedContext = getTrustedContext(node, name);
17872       allOrNothing = ALL_OR_NOTHING_ATTRS[name] || allOrNothing;
17873
17874       var interpolateFn = $interpolate(value, true, trustedContext, allOrNothing);
17875
17876       // no interpolation found -> ignore
17877       if (!interpolateFn) return;
17878
17879
17880       if (name === "multiple" && nodeName_(node) === "select") {
17881         throw $compileMinErr("selmulti",
17882             "Binding to the 'multiple' attribute is not supported. Element: {0}",
17883             startingTag(node));
17884       }
17885
17886       directives.push({
17887         priority: 100,
17888         compile: function() {
17889             return {
17890               pre: function attrInterpolatePreLinkFn(scope, element, attr) {
17891                 var $$observers = (attr.$$observers || (attr.$$observers = createMap()));
17892
17893                 if (EVENT_HANDLER_ATTR_REGEXP.test(name)) {
17894                   throw $compileMinErr('nodomevents',
17895                       "Interpolations for HTML DOM event attributes are disallowed.  Please use the " +
17896                           "ng- versions (such as ng-click instead of onclick) instead.");
17897                 }
17898
17899                 // If the attribute has changed since last $interpolate()ed
17900                 var newValue = attr[name];
17901                 if (newValue !== value) {
17902                   // we need to interpolate again since the attribute value has been updated
17903                   // (e.g. by another directive's compile function)
17904                   // ensure unset/empty values make interpolateFn falsy
17905                   interpolateFn = newValue && $interpolate(newValue, true, trustedContext, allOrNothing);
17906                   value = newValue;
17907                 }
17908
17909                 // if attribute was updated so that there is no interpolation going on we don't want to
17910                 // register any observers
17911                 if (!interpolateFn) return;
17912
17913                 // initialize attr object so that it's ready in case we need the value for isolate
17914                 // scope initialization, otherwise the value would not be available from isolate
17915                 // directive's linking fn during linking phase
17916                 attr[name] = interpolateFn(scope);
17917
17918                 ($$observers[name] || ($$observers[name] = [])).$$inter = true;
17919                 (attr.$$observers && attr.$$observers[name].$$scope || scope).
17920                   $watch(interpolateFn, function interpolateFnWatchAction(newValue, oldValue) {
17921                     //special case for class attribute addition + removal
17922                     //so that class changes can tap into the animation
17923                     //hooks provided by the $animate service. Be sure to
17924                     //skip animations when the first digest occurs (when
17925                     //both the new and the old values are the same) since
17926                     //the CSS classes are the non-interpolated values
17927                     if (name === 'class' && newValue != oldValue) {
17928                       attr.$updateClass(newValue, oldValue);
17929                     } else {
17930                       attr.$set(name, newValue);
17931                     }
17932                   });
17933               }
17934             };
17935           }
17936       });
17937     }
17938
17939
17940     /**
17941      * This is a special jqLite.replaceWith, which can replace items which
17942      * have no parents, provided that the containing jqLite collection is provided.
17943      *
17944      * @param {JqLite=} $rootElement The root of the compile tree. Used so that we can replace nodes
17945      *                               in the root of the tree.
17946      * @param {JqLite} elementsToRemove The jqLite element which we are going to replace. We keep
17947      *                                  the shell, but replace its DOM node reference.
17948      * @param {Node} newNode The new DOM node.
17949      */
17950     function replaceWith($rootElement, elementsToRemove, newNode) {
17951       var firstElementToRemove = elementsToRemove[0],
17952           removeCount = elementsToRemove.length,
17953           parent = firstElementToRemove.parentNode,
17954           i, ii;
17955
17956       if ($rootElement) {
17957         for (i = 0, ii = $rootElement.length; i < ii; i++) {
17958           if ($rootElement[i] == firstElementToRemove) {
17959             $rootElement[i++] = newNode;
17960             for (var j = i, j2 = j + removeCount - 1,
17961                      jj = $rootElement.length;
17962                  j < jj; j++, j2++) {
17963               if (j2 < jj) {
17964                 $rootElement[j] = $rootElement[j2];
17965               } else {
17966                 delete $rootElement[j];
17967               }
17968             }
17969             $rootElement.length -= removeCount - 1;
17970
17971             // If the replaced element is also the jQuery .context then replace it
17972             // .context is a deprecated jQuery api, so we should set it only when jQuery set it
17973             // http://api.jquery.com/context/
17974             if ($rootElement.context === firstElementToRemove) {
17975               $rootElement.context = newNode;
17976             }
17977             break;
17978           }
17979         }
17980       }
17981
17982       if (parent) {
17983         parent.replaceChild(newNode, firstElementToRemove);
17984       }
17985
17986       // TODO(perf): what's this document fragment for? is it needed? can we at least reuse it?
17987       var fragment = document.createDocumentFragment();
17988       fragment.appendChild(firstElementToRemove);
17989
17990       if (jqLite.hasData(firstElementToRemove)) {
17991         // Copy over user data (that includes Angular's $scope etc.). Don't copy private
17992         // data here because there's no public interface in jQuery to do that and copying over
17993         // event listeners (which is the main use of private data) wouldn't work anyway.
17994         jqLite.data(newNode, jqLite.data(firstElementToRemove));
17995
17996         // Remove data of the replaced element. We cannot just call .remove()
17997         // on the element it since that would deallocate scope that is needed
17998         // for the new node. Instead, remove the data "manually".
17999         if (!jQuery) {
18000           delete jqLite.cache[firstElementToRemove[jqLite.expando]];
18001         } else {
18002           // jQuery 2.x doesn't expose the data storage. Use jQuery.cleanData to clean up after
18003           // the replaced element. The cleanData version monkey-patched by Angular would cause
18004           // the scope to be trashed and we do need the very same scope to work with the new
18005           // element. However, we cannot just cache the non-patched version and use it here as
18006           // that would break if another library patches the method after Angular does (one
18007           // example is jQuery UI). Instead, set a flag indicating scope destroying should be
18008           // skipped this one time.
18009           skipDestroyOnNextJQueryCleanData = true;
18010           jQuery.cleanData([firstElementToRemove]);
18011         }
18012       }
18013
18014       for (var k = 1, kk = elementsToRemove.length; k < kk; k++) {
18015         var element = elementsToRemove[k];
18016         jqLite(element).remove(); // must do this way to clean up expando
18017         fragment.appendChild(element);
18018         delete elementsToRemove[k];
18019       }
18020
18021       elementsToRemove[0] = newNode;
18022       elementsToRemove.length = 1;
18023     }
18024
18025
18026     function cloneAndAnnotateFn(fn, annotation) {
18027       return extend(function() { return fn.apply(null, arguments); }, fn, annotation);
18028     }
18029
18030
18031     function invokeLinkFn(linkFn, scope, $element, attrs, controllers, transcludeFn) {
18032       try {
18033         linkFn(scope, $element, attrs, controllers, transcludeFn);
18034       } catch (e) {
18035         $exceptionHandler(e, startingTag($element));
18036       }
18037     }
18038
18039
18040     // Set up $watches for isolate scope and controller bindings. This process
18041     // only occurs for isolate scopes and new scopes with controllerAs.
18042     function initializeDirectiveBindings(scope, attrs, destination, bindings, directive) {
18043       var removeWatchCollection = [];
18044       forEach(bindings, function(definition, scopeName) {
18045         var attrName = definition.attrName,
18046         optional = definition.optional,
18047         mode = definition.mode, // @, =, or &
18048         lastValue,
18049         parentGet, parentSet, compare;
18050
18051         switch (mode) {
18052
18053           case '@':
18054             if (!optional && !hasOwnProperty.call(attrs, attrName)) {
18055               destination[scopeName] = attrs[attrName] = void 0;
18056             }
18057             attrs.$observe(attrName, function(value) {
18058               if (isString(value)) {
18059                 destination[scopeName] = value;
18060               }
18061             });
18062             attrs.$$observers[attrName].$$scope = scope;
18063             if (isString(attrs[attrName])) {
18064               // If the attribute has been provided then we trigger an interpolation to ensure
18065               // the value is there for use in the link fn
18066               destination[scopeName] = $interpolate(attrs[attrName])(scope);
18067             }
18068             break;
18069
18070           case '=':
18071             if (!hasOwnProperty.call(attrs, attrName)) {
18072               if (optional) break;
18073               attrs[attrName] = void 0;
18074             }
18075             if (optional && !attrs[attrName]) break;
18076
18077             parentGet = $parse(attrs[attrName]);
18078             if (parentGet.literal) {
18079               compare = equals;
18080             } else {
18081               compare = function(a, b) { return a === b || (a !== a && b !== b); };
18082             }
18083             parentSet = parentGet.assign || function() {
18084               // reset the change, or we will throw this exception on every $digest
18085               lastValue = destination[scopeName] = parentGet(scope);
18086               throw $compileMinErr('nonassign',
18087                   "Expression '{0}' used with directive '{1}' is non-assignable!",
18088                   attrs[attrName], directive.name);
18089             };
18090             lastValue = destination[scopeName] = parentGet(scope);
18091             var parentValueWatch = function parentValueWatch(parentValue) {
18092               if (!compare(parentValue, destination[scopeName])) {
18093                 // we are out of sync and need to copy
18094                 if (!compare(parentValue, lastValue)) {
18095                   // parent changed and it has precedence
18096                   destination[scopeName] = parentValue;
18097                 } else {
18098                   // if the parent can be assigned then do so
18099                   parentSet(scope, parentValue = destination[scopeName]);
18100                 }
18101               }
18102               return lastValue = parentValue;
18103             };
18104             parentValueWatch.$stateful = true;
18105             var removeWatch;
18106             if (definition.collection) {
18107               removeWatch = scope.$watchCollection(attrs[attrName], parentValueWatch);
18108             } else {
18109               removeWatch = scope.$watch($parse(attrs[attrName], parentValueWatch), null, parentGet.literal);
18110             }
18111             removeWatchCollection.push(removeWatch);
18112             break;
18113
18114           case '&':
18115             // Don't assign Object.prototype method to scope
18116             parentGet = attrs.hasOwnProperty(attrName) ? $parse(attrs[attrName]) : noop;
18117
18118             // Don't assign noop to destination if expression is not valid
18119             if (parentGet === noop && optional) break;
18120
18121             destination[scopeName] = function(locals) {
18122               return parentGet(scope, locals);
18123             };
18124             break;
18125         }
18126       });
18127
18128       return removeWatchCollection.length && function removeWatches() {
18129         for (var i = 0, ii = removeWatchCollection.length; i < ii; ++i) {
18130           removeWatchCollection[i]();
18131         }
18132       };
18133     }
18134   }];
18135 }
18136
18137 var PREFIX_REGEXP = /^((?:x|data)[\:\-_])/i;
18138 /**
18139  * Converts all accepted directives format into proper directive name.
18140  * @param name Name to normalize
18141  */
18142 function directiveNormalize(name) {
18143   return camelCase(name.replace(PREFIX_REGEXP, ''));
18144 }
18145
18146 /**
18147  * @ngdoc type
18148  * @name $compile.directive.Attributes
18149  *
18150  * @description
18151  * A shared object between directive compile / linking functions which contains normalized DOM
18152  * element attributes. The values reflect current binding state `{{ }}`. The normalization is
18153  * needed since all of these are treated as equivalent in Angular:
18154  *
18155  * ```
18156  *    <span ng:bind="a" ng-bind="a" data-ng-bind="a" x-ng-bind="a">
18157  * ```
18158  */
18159
18160 /**
18161  * @ngdoc property
18162  * @name $compile.directive.Attributes#$attr
18163  *
18164  * @description
18165  * A map of DOM element attribute names to the normalized name. This is
18166  * needed to do reverse lookup from normalized name back to actual name.
18167  */
18168
18169
18170 /**
18171  * @ngdoc method
18172  * @name $compile.directive.Attributes#$set
18173  * @kind function
18174  *
18175  * @description
18176  * Set DOM element attribute value.
18177  *
18178  *
18179  * @param {string} name Normalized element attribute name of the property to modify. The name is
18180  *          reverse-translated using the {@link ng.$compile.directive.Attributes#$attr $attr}
18181  *          property to the original name.
18182  * @param {string} value Value to set the attribute to. The value can be an interpolated string.
18183  */
18184
18185
18186
18187 /**
18188  * Closure compiler type information
18189  */
18190
18191 function nodesetLinkingFn(
18192   /* angular.Scope */ scope,
18193   /* NodeList */ nodeList,
18194   /* Element */ rootElement,
18195   /* function(Function) */ boundTranscludeFn
18196 ) {}
18197
18198 function directiveLinkingFn(
18199   /* nodesetLinkingFn */ nodesetLinkingFn,
18200   /* angular.Scope */ scope,
18201   /* Node */ node,
18202   /* Element */ rootElement,
18203   /* function(Function) */ boundTranscludeFn
18204 ) {}
18205
18206 function tokenDifference(str1, str2) {
18207   var values = '',
18208       tokens1 = str1.split(/\s+/),
18209       tokens2 = str2.split(/\s+/);
18210
18211   outer:
18212   for (var i = 0; i < tokens1.length; i++) {
18213     var token = tokens1[i];
18214     for (var j = 0; j < tokens2.length; j++) {
18215       if (token == tokens2[j]) continue outer;
18216     }
18217     values += (values.length > 0 ? ' ' : '') + token;
18218   }
18219   return values;
18220 }
18221
18222 function removeComments(jqNodes) {
18223   jqNodes = jqLite(jqNodes);
18224   var i = jqNodes.length;
18225
18226   if (i <= 1) {
18227     return jqNodes;
18228   }
18229
18230   while (i--) {
18231     var node = jqNodes[i];
18232     if (node.nodeType === NODE_TYPE_COMMENT) {
18233       splice.call(jqNodes, i, 1);
18234     }
18235   }
18236   return jqNodes;
18237 }
18238
18239 var $controllerMinErr = minErr('$controller');
18240
18241
18242 var CNTRL_REG = /^(\S+)(\s+as\s+(\w+))?$/;
18243 function identifierForController(controller, ident) {
18244   if (ident && isString(ident)) return ident;
18245   if (isString(controller)) {
18246     var match = CNTRL_REG.exec(controller);
18247     if (match) return match[3];
18248   }
18249 }
18250
18251
18252 /**
18253  * @ngdoc provider
18254  * @name $controllerProvider
18255  * @description
18256  * The {@link ng.$controller $controller service} is used by Angular to create new
18257  * controllers.
18258  *
18259  * This provider allows controller registration via the
18260  * {@link ng.$controllerProvider#register register} method.
18261  */
18262 function $ControllerProvider() {
18263   var controllers = {},
18264       globals = false;
18265
18266   /**
18267    * @ngdoc method
18268    * @name $controllerProvider#register
18269    * @param {string|Object} name Controller name, or an object map of controllers where the keys are
18270    *    the names and the values are the constructors.
18271    * @param {Function|Array} constructor Controller constructor fn (optionally decorated with DI
18272    *    annotations in the array notation).
18273    */
18274   this.register = function(name, constructor) {
18275     assertNotHasOwnProperty(name, 'controller');
18276     if (isObject(name)) {
18277       extend(controllers, name);
18278     } else {
18279       controllers[name] = constructor;
18280     }
18281   };
18282
18283   /**
18284    * @ngdoc method
18285    * @name $controllerProvider#allowGlobals
18286    * @description If called, allows `$controller` to find controller constructors on `window`
18287    */
18288   this.allowGlobals = function() {
18289     globals = true;
18290   };
18291
18292
18293   this.$get = ['$injector', '$window', function($injector, $window) {
18294
18295     /**
18296      * @ngdoc service
18297      * @name $controller
18298      * @requires $injector
18299      *
18300      * @param {Function|string} constructor If called with a function then it's considered to be the
18301      *    controller constructor function. Otherwise it's considered to be a string which is used
18302      *    to retrieve the controller constructor using the following steps:
18303      *
18304      *    * check if a controller with given name is registered via `$controllerProvider`
18305      *    * check if evaluating the string on the current scope returns a constructor
18306      *    * if $controllerProvider#allowGlobals, check `window[constructor]` on the global
18307      *      `window` object (not recommended)
18308      *
18309      *    The string can use the `controller as property` syntax, where the controller instance is published
18310      *    as the specified property on the `scope`; the `scope` must be injected into `locals` param for this
18311      *    to work correctly.
18312      *
18313      * @param {Object} locals Injection locals for Controller.
18314      * @return {Object} Instance of given controller.
18315      *
18316      * @description
18317      * `$controller` service is responsible for instantiating controllers.
18318      *
18319      * It's just a simple call to {@link auto.$injector $injector}, but extracted into
18320      * a service, so that one can override this service with [BC version](https://gist.github.com/1649788).
18321      */
18322     return function(expression, locals, later, ident) {
18323       // PRIVATE API:
18324       //   param `later` --- indicates that the controller's constructor is invoked at a later time.
18325       //                     If true, $controller will allocate the object with the correct
18326       //                     prototype chain, but will not invoke the controller until a returned
18327       //                     callback is invoked.
18328       //   param `ident` --- An optional label which overrides the label parsed from the controller
18329       //                     expression, if any.
18330       var instance, match, constructor, identifier;
18331       later = later === true;
18332       if (ident && isString(ident)) {
18333         identifier = ident;
18334       }
18335
18336       if (isString(expression)) {
18337         match = expression.match(CNTRL_REG);
18338         if (!match) {
18339           throw $controllerMinErr('ctrlfmt',
18340             "Badly formed controller string '{0}'. " +
18341             "Must match `__name__ as __id__` or `__name__`.", expression);
18342         }
18343         constructor = match[1],
18344         identifier = identifier || match[3];
18345         expression = controllers.hasOwnProperty(constructor)
18346             ? controllers[constructor]
18347             : getter(locals.$scope, constructor, true) ||
18348                 (globals ? getter($window, constructor, true) : undefined);
18349
18350         assertArgFn(expression, constructor, true);
18351       }
18352
18353       if (later) {
18354         // Instantiate controller later:
18355         // This machinery is used to create an instance of the object before calling the
18356         // controller's constructor itself.
18357         //
18358         // This allows properties to be added to the controller before the constructor is
18359         // invoked. Primarily, this is used for isolate scope bindings in $compile.
18360         //
18361         // This feature is not intended for use by applications, and is thus not documented
18362         // publicly.
18363         // Object creation: http://jsperf.com/create-constructor/2
18364         var controllerPrototype = (isArray(expression) ?
18365           expression[expression.length - 1] : expression).prototype;
18366         instance = Object.create(controllerPrototype || null);
18367
18368         if (identifier) {
18369           addIdentifier(locals, identifier, instance, constructor || expression.name);
18370         }
18371
18372         var instantiate;
18373         return instantiate = extend(function() {
18374           var result = $injector.invoke(expression, instance, locals, constructor);
18375           if (result !== instance && (isObject(result) || isFunction(result))) {
18376             instance = result;
18377             if (identifier) {
18378               // If result changed, re-assign controllerAs value to scope.
18379               addIdentifier(locals, identifier, instance, constructor || expression.name);
18380             }
18381           }
18382           return instance;
18383         }, {
18384           instance: instance,
18385           identifier: identifier
18386         });
18387       }
18388
18389       instance = $injector.instantiate(expression, locals, constructor);
18390
18391       if (identifier) {
18392         addIdentifier(locals, identifier, instance, constructor || expression.name);
18393       }
18394
18395       return instance;
18396     };
18397
18398     function addIdentifier(locals, identifier, instance, name) {
18399       if (!(locals && isObject(locals.$scope))) {
18400         throw minErr('$controller')('noscp',
18401           "Cannot export controller '{0}' as '{1}'! No $scope object provided via `locals`.",
18402           name, identifier);
18403       }
18404
18405       locals.$scope[identifier] = instance;
18406     }
18407   }];
18408 }
18409
18410 /**
18411  * @ngdoc service
18412  * @name $document
18413  * @requires $window
18414  *
18415  * @description
18416  * A {@link angular.element jQuery or jqLite} wrapper for the browser's `window.document` object.
18417  *
18418  * @example
18419    <example module="documentExample">
18420      <file name="index.html">
18421        <div ng-controller="ExampleController">
18422          <p>$document title: <b ng-bind="title"></b></p>
18423          <p>window.document title: <b ng-bind="windowTitle"></b></p>
18424        </div>
18425      </file>
18426      <file name="script.js">
18427        angular.module('documentExample', [])
18428          .controller('ExampleController', ['$scope', '$document', function($scope, $document) {
18429            $scope.title = $document[0].title;
18430            $scope.windowTitle = angular.element(window.document)[0].title;
18431          }]);
18432      </file>
18433    </example>
18434  */
18435 function $DocumentProvider() {
18436   this.$get = ['$window', function(window) {
18437     return jqLite(window.document);
18438   }];
18439 }
18440
18441 /**
18442  * @ngdoc service
18443  * @name $exceptionHandler
18444  * @requires ng.$log
18445  *
18446  * @description
18447  * Any uncaught exception in angular expressions is delegated to this service.
18448  * The default implementation simply delegates to `$log.error` which logs it into
18449  * the browser console.
18450  *
18451  * In unit tests, if `angular-mocks.js` is loaded, this service is overridden by
18452  * {@link ngMock.$exceptionHandler mock $exceptionHandler} which aids in testing.
18453  *
18454  * ## Example:
18455  *
18456  * ```js
18457  *   angular.module('exceptionOverride', []).factory('$exceptionHandler', function() {
18458  *     return function(exception, cause) {
18459  *       exception.message += ' (caused by "' + cause + '")';
18460  *       throw exception;
18461  *     };
18462  *   });
18463  * ```
18464  *
18465  * This example will override the normal action of `$exceptionHandler`, to make angular
18466  * exceptions fail hard when they happen, instead of just logging to the console.
18467  *
18468  * <hr />
18469  * Note, that code executed in event-listeners (even those registered using jqLite's `on`/`bind`
18470  * methods) does not delegate exceptions to the {@link ng.$exceptionHandler $exceptionHandler}
18471  * (unless executed during a digest).
18472  *
18473  * If you wish, you can manually delegate exceptions, e.g.
18474  * `try { ... } catch(e) { $exceptionHandler(e); }`
18475  *
18476  * @param {Error} exception Exception associated with the error.
18477  * @param {string=} cause optional information about the context in which
18478  *       the error was thrown.
18479  *
18480  */
18481 function $ExceptionHandlerProvider() {
18482   this.$get = ['$log', function($log) {
18483     return function(exception, cause) {
18484       $log.error.apply($log, arguments);
18485     };
18486   }];
18487 }
18488
18489 var $$ForceReflowProvider = function() {
18490   this.$get = ['$document', function($document) {
18491     return function(domNode) {
18492       //the line below will force the browser to perform a repaint so
18493       //that all the animated elements within the animation frame will
18494       //be properly updated and drawn on screen. This is required to
18495       //ensure that the preparation animation is properly flushed so that
18496       //the active state picks up from there. DO NOT REMOVE THIS LINE.
18497       //DO NOT OPTIMIZE THIS LINE. THE MINIFIER WILL REMOVE IT OTHERWISE WHICH
18498       //WILL RESULT IN AN UNPREDICTABLE BUG THAT IS VERY HARD TO TRACK DOWN AND
18499       //WILL TAKE YEARS AWAY FROM YOUR LIFE.
18500       if (domNode) {
18501         if (!domNode.nodeType && domNode instanceof jqLite) {
18502           domNode = domNode[0];
18503         }
18504       } else {
18505         domNode = $document[0].body;
18506       }
18507       return domNode.offsetWidth + 1;
18508     };
18509   }];
18510 };
18511
18512 var APPLICATION_JSON = 'application/json';
18513 var CONTENT_TYPE_APPLICATION_JSON = {'Content-Type': APPLICATION_JSON + ';charset=utf-8'};
18514 var JSON_START = /^\[|^\{(?!\{)/;
18515 var JSON_ENDS = {
18516   '[': /]$/,
18517   '{': /}$/
18518 };
18519 var JSON_PROTECTION_PREFIX = /^\)\]\}',?\n/;
18520 var $httpMinErr = minErr('$http');
18521 var $httpMinErrLegacyFn = function(method) {
18522   return function() {
18523     throw $httpMinErr('legacy', 'The method `{0}` on the promise returned from `$http` has been disabled.', method);
18524   };
18525 };
18526
18527 function serializeValue(v) {
18528   if (isObject(v)) {
18529     return isDate(v) ? v.toISOString() : toJson(v);
18530   }
18531   return v;
18532 }
18533
18534
18535 function $HttpParamSerializerProvider() {
18536   /**
18537    * @ngdoc service
18538    * @name $httpParamSerializer
18539    * @description
18540    *
18541    * Default {@link $http `$http`} params serializer that converts objects to strings
18542    * according to the following rules:
18543    *
18544    * * `{'foo': 'bar'}` results in `foo=bar`
18545    * * `{'foo': Date.now()}` results in `foo=2015-04-01T09%3A50%3A49.262Z` (`toISOString()` and encoded representation of a Date object)
18546    * * `{'foo': ['bar', 'baz']}` results in `foo=bar&foo=baz` (repeated key for each array element)
18547    * * `{'foo': {'bar':'baz'}}` results in `foo=%7B%22bar%22%3A%22baz%22%7D"` (stringified and encoded representation of an object)
18548    *
18549    * Note that serializer will sort the request parameters alphabetically.
18550    * */
18551
18552   this.$get = function() {
18553     return function ngParamSerializer(params) {
18554       if (!params) return '';
18555       var parts = [];
18556       forEachSorted(params, function(value, key) {
18557         if (value === null || isUndefined(value)) return;
18558         if (isArray(value)) {
18559           forEach(value, function(v, k) {
18560             parts.push(encodeUriQuery(key)  + '=' + encodeUriQuery(serializeValue(v)));
18561           });
18562         } else {
18563           parts.push(encodeUriQuery(key) + '=' + encodeUriQuery(serializeValue(value)));
18564         }
18565       });
18566
18567       return parts.join('&');
18568     };
18569   };
18570 }
18571
18572 function $HttpParamSerializerJQLikeProvider() {
18573   /**
18574    * @ngdoc service
18575    * @name $httpParamSerializerJQLike
18576    * @description
18577    *
18578    * Alternative {@link $http `$http`} params serializer that follows
18579    * jQuery's [`param()`](http://api.jquery.com/jquery.param/) method logic.
18580    * The serializer will also sort the params alphabetically.
18581    *
18582    * To use it for serializing `$http` request parameters, set it as the `paramSerializer` property:
18583    *
18584    * ```js
18585    * $http({
18586    *   url: myUrl,
18587    *   method: 'GET',
18588    *   params: myParams,
18589    *   paramSerializer: '$httpParamSerializerJQLike'
18590    * });
18591    * ```
18592    *
18593    * It is also possible to set it as the default `paramSerializer` in the
18594    * {@link $httpProvider#defaults `$httpProvider`}.
18595    *
18596    * Additionally, you can inject the serializer and use it explicitly, for example to serialize
18597    * form data for submission:
18598    *
18599    * ```js
18600    * .controller(function($http, $httpParamSerializerJQLike) {
18601    *   //...
18602    *
18603    *   $http({
18604    *     url: myUrl,
18605    *     method: 'POST',
18606    *     data: $httpParamSerializerJQLike(myData),
18607    *     headers: {
18608    *       'Content-Type': 'application/x-www-form-urlencoded'
18609    *     }
18610    *   });
18611    *
18612    * });
18613    * ```
18614    *
18615    * */
18616   this.$get = function() {
18617     return function jQueryLikeParamSerializer(params) {
18618       if (!params) return '';
18619       var parts = [];
18620       serialize(params, '', true);
18621       return parts.join('&');
18622
18623       function serialize(toSerialize, prefix, topLevel) {
18624         if (toSerialize === null || isUndefined(toSerialize)) return;
18625         if (isArray(toSerialize)) {
18626           forEach(toSerialize, function(value, index) {
18627             serialize(value, prefix + '[' + (isObject(value) ? index : '') + ']');
18628           });
18629         } else if (isObject(toSerialize) && !isDate(toSerialize)) {
18630           forEachSorted(toSerialize, function(value, key) {
18631             serialize(value, prefix +
18632                 (topLevel ? '' : '[') +
18633                 key +
18634                 (topLevel ? '' : ']'));
18635           });
18636         } else {
18637           parts.push(encodeUriQuery(prefix) + '=' + encodeUriQuery(serializeValue(toSerialize)));
18638         }
18639       }
18640     };
18641   };
18642 }
18643
18644 function defaultHttpResponseTransform(data, headers) {
18645   if (isString(data)) {
18646     // Strip json vulnerability protection prefix and trim whitespace
18647     var tempData = data.replace(JSON_PROTECTION_PREFIX, '').trim();
18648
18649     if (tempData) {
18650       var contentType = headers('Content-Type');
18651       if ((contentType && (contentType.indexOf(APPLICATION_JSON) === 0)) || isJsonLike(tempData)) {
18652         data = fromJson(tempData);
18653       }
18654     }
18655   }
18656
18657   return data;
18658 }
18659
18660 function isJsonLike(str) {
18661     var jsonStart = str.match(JSON_START);
18662     return jsonStart && JSON_ENDS[jsonStart[0]].test(str);
18663 }
18664
18665 /**
18666  * Parse headers into key value object
18667  *
18668  * @param {string} headers Raw headers as a string
18669  * @returns {Object} Parsed headers as key value object
18670  */
18671 function parseHeaders(headers) {
18672   var parsed = createMap(), i;
18673
18674   function fillInParsed(key, val) {
18675     if (key) {
18676       parsed[key] = parsed[key] ? parsed[key] + ', ' + val : val;
18677     }
18678   }
18679
18680   if (isString(headers)) {
18681     forEach(headers.split('\n'), function(line) {
18682       i = line.indexOf(':');
18683       fillInParsed(lowercase(trim(line.substr(0, i))), trim(line.substr(i + 1)));
18684     });
18685   } else if (isObject(headers)) {
18686     forEach(headers, function(headerVal, headerKey) {
18687       fillInParsed(lowercase(headerKey), trim(headerVal));
18688     });
18689   }
18690
18691   return parsed;
18692 }
18693
18694
18695 /**
18696  * Returns a function that provides access to parsed headers.
18697  *
18698  * Headers are lazy parsed when first requested.
18699  * @see parseHeaders
18700  *
18701  * @param {(string|Object)} headers Headers to provide access to.
18702  * @returns {function(string=)} Returns a getter function which if called with:
18703  *
18704  *   - if called with single an argument returns a single header value or null
18705  *   - if called with no arguments returns an object containing all headers.
18706  */
18707 function headersGetter(headers) {
18708   var headersObj;
18709
18710   return function(name) {
18711     if (!headersObj) headersObj =  parseHeaders(headers);
18712
18713     if (name) {
18714       var value = headersObj[lowercase(name)];
18715       if (value === void 0) {
18716         value = null;
18717       }
18718       return value;
18719     }
18720
18721     return headersObj;
18722   };
18723 }
18724
18725
18726 /**
18727  * Chain all given functions
18728  *
18729  * This function is used for both request and response transforming
18730  *
18731  * @param {*} data Data to transform.
18732  * @param {function(string=)} headers HTTP headers getter fn.
18733  * @param {number} status HTTP status code of the response.
18734  * @param {(Function|Array.<Function>)} fns Function or an array of functions.
18735  * @returns {*} Transformed data.
18736  */
18737 function transformData(data, headers, status, fns) {
18738   if (isFunction(fns)) {
18739     return fns(data, headers, status);
18740   }
18741
18742   forEach(fns, function(fn) {
18743     data = fn(data, headers, status);
18744   });
18745
18746   return data;
18747 }
18748
18749
18750 function isSuccess(status) {
18751   return 200 <= status && status < 300;
18752 }
18753
18754
18755 /**
18756  * @ngdoc provider
18757  * @name $httpProvider
18758  * @description
18759  * Use `$httpProvider` to change the default behavior of the {@link ng.$http $http} service.
18760  * */
18761 function $HttpProvider() {
18762   /**
18763    * @ngdoc property
18764    * @name $httpProvider#defaults
18765    * @description
18766    *
18767    * Object containing default values for all {@link ng.$http $http} requests.
18768    *
18769    * - **`defaults.cache`** - {Object} - an object built with {@link ng.$cacheFactory `$cacheFactory`}
18770    * that will provide the cache for all requests who set their `cache` property to `true`.
18771    * If you set the `defaults.cache = false` then only requests that specify their own custom
18772    * cache object will be cached. See {@link $http#caching $http Caching} for more information.
18773    *
18774    * - **`defaults.xsrfCookieName`** - {string} - Name of cookie containing the XSRF token.
18775    * Defaults value is `'XSRF-TOKEN'`.
18776    *
18777    * - **`defaults.xsrfHeaderName`** - {string} - Name of HTTP header to populate with the
18778    * XSRF token. Defaults value is `'X-XSRF-TOKEN'`.
18779    *
18780    * - **`defaults.headers`** - {Object} - Default headers for all $http requests.
18781    * Refer to {@link ng.$http#setting-http-headers $http} for documentation on
18782    * setting default headers.
18783    *     - **`defaults.headers.common`**
18784    *     - **`defaults.headers.post`**
18785    *     - **`defaults.headers.put`**
18786    *     - **`defaults.headers.patch`**
18787    *
18788    *
18789    * - **`defaults.paramSerializer`** - `{string|function(Object<string,string>):string}` - A function
18790    *  used to the prepare string representation of request parameters (specified as an object).
18791    *  If specified as string, it is interpreted as a function registered with the {@link auto.$injector $injector}.
18792    *  Defaults to {@link ng.$httpParamSerializer $httpParamSerializer}.
18793    *
18794    **/
18795   var defaults = this.defaults = {
18796     // transform incoming response data
18797     transformResponse: [defaultHttpResponseTransform],
18798
18799     // transform outgoing request data
18800     transformRequest: [function(d) {
18801       return isObject(d) && !isFile(d) && !isBlob(d) && !isFormData(d) ? toJson(d) : d;
18802     }],
18803
18804     // default headers
18805     headers: {
18806       common: {
18807         'Accept': 'application/json, text/plain, */*'
18808       },
18809       post:   shallowCopy(CONTENT_TYPE_APPLICATION_JSON),
18810       put:    shallowCopy(CONTENT_TYPE_APPLICATION_JSON),
18811       patch:  shallowCopy(CONTENT_TYPE_APPLICATION_JSON)
18812     },
18813
18814     xsrfCookieName: 'XSRF-TOKEN',
18815     xsrfHeaderName: 'X-XSRF-TOKEN',
18816
18817     paramSerializer: '$httpParamSerializer'
18818   };
18819
18820   var useApplyAsync = false;
18821   /**
18822    * @ngdoc method
18823    * @name $httpProvider#useApplyAsync
18824    * @description
18825    *
18826    * Configure $http service to combine processing of multiple http responses received at around
18827    * the same time via {@link ng.$rootScope.Scope#$applyAsync $rootScope.$applyAsync}. This can result in
18828    * significant performance improvement for bigger applications that make many HTTP requests
18829    * concurrently (common during application bootstrap).
18830    *
18831    * Defaults to false. If no value is specified, returns the current configured value.
18832    *
18833    * @param {boolean=} value If true, when requests are loaded, they will schedule a deferred
18834    *    "apply" on the next tick, giving time for subsequent requests in a roughly ~10ms window
18835    *    to load and share the same digest cycle.
18836    *
18837    * @returns {boolean|Object} If a value is specified, returns the $httpProvider for chaining.
18838    *    otherwise, returns the current configured value.
18839    **/
18840   this.useApplyAsync = function(value) {
18841     if (isDefined(value)) {
18842       useApplyAsync = !!value;
18843       return this;
18844     }
18845     return useApplyAsync;
18846   };
18847
18848   var useLegacyPromise = true;
18849   /**
18850    * @ngdoc method
18851    * @name $httpProvider#useLegacyPromiseExtensions
18852    * @description
18853    *
18854    * Configure `$http` service to return promises without the shorthand methods `success` and `error`.
18855    * This should be used to make sure that applications work without these methods.
18856    *
18857    * Defaults to true. If no value is specified, returns the current configured value.
18858    *
18859    * @param {boolean=} value If true, `$http` will return a promise with the deprecated legacy `success` and `error` methods.
18860    *
18861    * @returns {boolean|Object} If a value is specified, returns the $httpProvider for chaining.
18862    *    otherwise, returns the current configured value.
18863    **/
18864   this.useLegacyPromiseExtensions = function(value) {
18865     if (isDefined(value)) {
18866       useLegacyPromise = !!value;
18867       return this;
18868     }
18869     return useLegacyPromise;
18870   };
18871
18872   /**
18873    * @ngdoc property
18874    * @name $httpProvider#interceptors
18875    * @description
18876    *
18877    * Array containing service factories for all synchronous or asynchronous {@link ng.$http $http}
18878    * pre-processing of request or postprocessing of responses.
18879    *
18880    * These service factories are ordered by request, i.e. they are applied in the same order as the
18881    * array, on request, but reverse order, on response.
18882    *
18883    * {@link ng.$http#interceptors Interceptors detailed info}
18884    **/
18885   var interceptorFactories = this.interceptors = [];
18886
18887   this.$get = ['$httpBackend', '$$cookieReader', '$cacheFactory', '$rootScope', '$q', '$injector',
18888       function($httpBackend, $$cookieReader, $cacheFactory, $rootScope, $q, $injector) {
18889
18890     var defaultCache = $cacheFactory('$http');
18891
18892     /**
18893      * Make sure that default param serializer is exposed as a function
18894      */
18895     defaults.paramSerializer = isString(defaults.paramSerializer) ?
18896       $injector.get(defaults.paramSerializer) : defaults.paramSerializer;
18897
18898     /**
18899      * Interceptors stored in reverse order. Inner interceptors before outer interceptors.
18900      * The reversal is needed so that we can build up the interception chain around the
18901      * server request.
18902      */
18903     var reversedInterceptors = [];
18904
18905     forEach(interceptorFactories, function(interceptorFactory) {
18906       reversedInterceptors.unshift(isString(interceptorFactory)
18907           ? $injector.get(interceptorFactory) : $injector.invoke(interceptorFactory));
18908     });
18909
18910     /**
18911      * @ngdoc service
18912      * @kind function
18913      * @name $http
18914      * @requires ng.$httpBackend
18915      * @requires $cacheFactory
18916      * @requires $rootScope
18917      * @requires $q
18918      * @requires $injector
18919      *
18920      * @description
18921      * The `$http` service is a core Angular service that facilitates communication with the remote
18922      * HTTP servers via the browser's [XMLHttpRequest](https://developer.mozilla.org/en/xmlhttprequest)
18923      * object or via [JSONP](http://en.wikipedia.org/wiki/JSONP).
18924      *
18925      * For unit testing applications that use `$http` service, see
18926      * {@link ngMock.$httpBackend $httpBackend mock}.
18927      *
18928      * For a higher level of abstraction, please check out the {@link ngResource.$resource
18929      * $resource} service.
18930      *
18931      * The $http API is based on the {@link ng.$q deferred/promise APIs} exposed by
18932      * the $q service. While for simple usage patterns this doesn't matter much, for advanced usage
18933      * it is important to familiarize yourself with these APIs and the guarantees they provide.
18934      *
18935      *
18936      * ## General usage
18937      * The `$http` service is a function which takes a single argument — a {@link $http#usage configuration object} —
18938      * that is used to generate an HTTP request and returns  a {@link ng.$q promise}.
18939      *
18940      * ```js
18941      *   // Simple GET request example:
18942      *   $http({
18943      *     method: 'GET',
18944      *     url: '/someUrl'
18945      *   }).then(function successCallback(response) {
18946      *       // this callback will be called asynchronously
18947      *       // when the response is available
18948      *     }, function errorCallback(response) {
18949      *       // called asynchronously if an error occurs
18950      *       // or server returns response with an error status.
18951      *     });
18952      * ```
18953      *
18954      * The response object has these properties:
18955      *
18956      *   - **data** – `{string|Object}` – The response body transformed with the transform
18957      *     functions.
18958      *   - **status** – `{number}` – HTTP status code of the response.
18959      *   - **headers** – `{function([headerName])}` – Header getter function.
18960      *   - **config** – `{Object}` – The configuration object that was used to generate the request.
18961      *   - **statusText** – `{string}` – HTTP status text of the response.
18962      *
18963      * A response status code between 200 and 299 is considered a success status and
18964      * will result in the success callback being called. Note that if the response is a redirect,
18965      * XMLHttpRequest will transparently follow it, meaning that the error callback will not be
18966      * called for such responses.
18967      *
18968      *
18969      * ## Shortcut methods
18970      *
18971      * Shortcut methods are also available. All shortcut methods require passing in the URL, and
18972      * request data must be passed in for POST/PUT requests. An optional config can be passed as the
18973      * last argument.
18974      *
18975      * ```js
18976      *   $http.get('/someUrl', config).then(successCallback, errorCallback);
18977      *   $http.post('/someUrl', data, config).then(successCallback, errorCallback);
18978      * ```
18979      *
18980      * Complete list of shortcut methods:
18981      *
18982      * - {@link ng.$http#get $http.get}
18983      * - {@link ng.$http#head $http.head}
18984      * - {@link ng.$http#post $http.post}
18985      * - {@link ng.$http#put $http.put}
18986      * - {@link ng.$http#delete $http.delete}
18987      * - {@link ng.$http#jsonp $http.jsonp}
18988      * - {@link ng.$http#patch $http.patch}
18989      *
18990      *
18991      * ## Writing Unit Tests that use $http
18992      * When unit testing (using {@link ngMock ngMock}), it is necessary to call
18993      * {@link ngMock.$httpBackend#flush $httpBackend.flush()} to flush each pending
18994      * request using trained responses.
18995      *
18996      * ```
18997      * $httpBackend.expectGET(...);
18998      * $http.get(...);
18999      * $httpBackend.flush();
19000      * ```
19001      *
19002      * ## Deprecation Notice
19003      * <div class="alert alert-danger">
19004      *   The `$http` legacy promise methods `success` and `error` have been deprecated.
19005      *   Use the standard `then` method instead.
19006      *   If {@link $httpProvider#useLegacyPromiseExtensions `$httpProvider.useLegacyPromiseExtensions`} is set to
19007      *   `false` then these methods will throw {@link $http:legacy `$http/legacy`} error.
19008      * </div>
19009      *
19010      * ## Setting HTTP Headers
19011      *
19012      * The $http service will automatically add certain HTTP headers to all requests. These defaults
19013      * can be fully configured by accessing the `$httpProvider.defaults.headers` configuration
19014      * object, which currently contains this default configuration:
19015      *
19016      * - `$httpProvider.defaults.headers.common` (headers that are common for all requests):
19017      *   - `Accept: application/json, text/plain, * / *`
19018      * - `$httpProvider.defaults.headers.post`: (header defaults for POST requests)
19019      *   - `Content-Type: application/json`
19020      * - `$httpProvider.defaults.headers.put` (header defaults for PUT requests)
19021      *   - `Content-Type: application/json`
19022      *
19023      * To add or overwrite these defaults, simply add or remove a property from these configuration
19024      * objects. To add headers for an HTTP method other than POST or PUT, simply add a new object
19025      * with the lowercased HTTP method name as the key, e.g.
19026      * `$httpProvider.defaults.headers.get = { 'My-Header' : 'value' }`.
19027      *
19028      * The defaults can also be set at runtime via the `$http.defaults` object in the same
19029      * fashion. For example:
19030      *
19031      * ```
19032      * module.run(function($http) {
19033      *   $http.defaults.headers.common.Authorization = 'Basic YmVlcDpib29w'
19034      * });
19035      * ```
19036      *
19037      * In addition, you can supply a `headers` property in the config object passed when
19038      * calling `$http(config)`, which overrides the defaults without changing them globally.
19039      *
19040      * To explicitly remove a header automatically added via $httpProvider.defaults.headers on a per request basis,
19041      * Use the `headers` property, setting the desired header to `undefined`. For example:
19042      *
19043      * ```js
19044      * var req = {
19045      *  method: 'POST',
19046      *  url: 'http://example.com',
19047      *  headers: {
19048      *    'Content-Type': undefined
19049      *  },
19050      *  data: { test: 'test' }
19051      * }
19052      *
19053      * $http(req).then(function(){...}, function(){...});
19054      * ```
19055      *
19056      * ## Transforming Requests and Responses
19057      *
19058      * Both requests and responses can be transformed using transformation functions: `transformRequest`
19059      * and `transformResponse`. These properties can be a single function that returns
19060      * the transformed value (`function(data, headersGetter, status)`) or an array of such transformation functions,
19061      * which allows you to `push` or `unshift` a new transformation function into the transformation chain.
19062      *
19063      * ### Default Transformations
19064      *
19065      * The `$httpProvider` provider and `$http` service expose `defaults.transformRequest` and
19066      * `defaults.transformResponse` properties. If a request does not provide its own transformations
19067      * then these will be applied.
19068      *
19069      * You can augment or replace the default transformations by modifying these properties by adding to or
19070      * replacing the array.
19071      *
19072      * Angular provides the following default transformations:
19073      *
19074      * Request transformations (`$httpProvider.defaults.transformRequest` and `$http.defaults.transformRequest`):
19075      *
19076      * - If the `data` property of the request configuration object contains an object, serialize it
19077      *   into JSON format.
19078      *
19079      * Response transformations (`$httpProvider.defaults.transformResponse` and `$http.defaults.transformResponse`):
19080      *
19081      *  - If XSRF prefix is detected, strip it (see Security Considerations section below).
19082      *  - If JSON response is detected, deserialize it using a JSON parser.
19083      *
19084      *
19085      * ### Overriding the Default Transformations Per Request
19086      *
19087      * If you wish override the request/response transformations only for a single request then provide
19088      * `transformRequest` and/or `transformResponse` properties on the configuration object passed
19089      * into `$http`.
19090      *
19091      * Note that if you provide these properties on the config object the default transformations will be
19092      * overwritten. If you wish to augment the default transformations then you must include them in your
19093      * local transformation array.
19094      *
19095      * The following code demonstrates adding a new response transformation to be run after the default response
19096      * transformations have been run.
19097      *
19098      * ```js
19099      * function appendTransform(defaults, transform) {
19100      *
19101      *   // We can't guarantee that the default transformation is an array
19102      *   defaults = angular.isArray(defaults) ? defaults : [defaults];
19103      *
19104      *   // Append the new transformation to the defaults
19105      *   return defaults.concat(transform);
19106      * }
19107      *
19108      * $http({
19109      *   url: '...',
19110      *   method: 'GET',
19111      *   transformResponse: appendTransform($http.defaults.transformResponse, function(value) {
19112      *     return doTransform(value);
19113      *   })
19114      * });
19115      * ```
19116      *
19117      *
19118      * ## Caching
19119      *
19120      * To enable caching, set the request configuration `cache` property to `true` (to use default
19121      * cache) or to a custom cache object (built with {@link ng.$cacheFactory `$cacheFactory`}).
19122      * When the cache is enabled, `$http` stores the response from the server in the specified
19123      * cache. The next time the same request is made, the response is served from the cache without
19124      * sending a request to the server.
19125      *
19126      * Note that even if the response is served from cache, delivery of the data is asynchronous in
19127      * the same way that real requests are.
19128      *
19129      * If there are multiple GET requests for the same URL that should be cached using the same
19130      * cache, but the cache is not populated yet, only one request to the server will be made and
19131      * the remaining requests will be fulfilled using the response from the first request.
19132      *
19133      * You can change the default cache to a new object (built with
19134      * {@link ng.$cacheFactory `$cacheFactory`}) by updating the
19135      * {@link ng.$http#defaults `$http.defaults.cache`} property. All requests who set
19136      * their `cache` property to `true` will now use this cache object.
19137      *
19138      * If you set the default cache to `false` then only requests that specify their own custom
19139      * cache object will be cached.
19140      *
19141      * ## Interceptors
19142      *
19143      * Before you start creating interceptors, be sure to understand the
19144      * {@link ng.$q $q and deferred/promise APIs}.
19145      *
19146      * For purposes of global error handling, authentication, or any kind of synchronous or
19147      * asynchronous pre-processing of request or postprocessing of responses, it is desirable to be
19148      * able to intercept requests before they are handed to the server and
19149      * responses before they are handed over to the application code that
19150      * initiated these requests. The interceptors leverage the {@link ng.$q
19151      * promise APIs} to fulfill this need for both synchronous and asynchronous pre-processing.
19152      *
19153      * The interceptors are service factories that are registered with the `$httpProvider` by
19154      * adding them to the `$httpProvider.interceptors` array. The factory is called and
19155      * injected with dependencies (if specified) and returns the interceptor.
19156      *
19157      * There are two kinds of interceptors (and two kinds of rejection interceptors):
19158      *
19159      *   * `request`: interceptors get called with a http {@link $http#usage config} object. The function is free to
19160      *     modify the `config` object or create a new one. The function needs to return the `config`
19161      *     object directly, or a promise containing the `config` or a new `config` object.
19162      *   * `requestError`: interceptor gets called when a previous interceptor threw an error or
19163      *     resolved with a rejection.
19164      *   * `response`: interceptors get called with http `response` object. The function is free to
19165      *     modify the `response` object or create a new one. The function needs to return the `response`
19166      *     object directly, or as a promise containing the `response` or a new `response` object.
19167      *   * `responseError`: interceptor gets called when a previous interceptor threw an error or
19168      *     resolved with a rejection.
19169      *
19170      *
19171      * ```js
19172      *   // register the interceptor as a service
19173      *   $provide.factory('myHttpInterceptor', function($q, dependency1, dependency2) {
19174      *     return {
19175      *       // optional method
19176      *       'request': function(config) {
19177      *         // do something on success
19178      *         return config;
19179      *       },
19180      *
19181      *       // optional method
19182      *      'requestError': function(rejection) {
19183      *         // do something on error
19184      *         if (canRecover(rejection)) {
19185      *           return responseOrNewPromise
19186      *         }
19187      *         return $q.reject(rejection);
19188      *       },
19189      *
19190      *
19191      *
19192      *       // optional method
19193      *       'response': function(response) {
19194      *         // do something on success
19195      *         return response;
19196      *       },
19197      *
19198      *       // optional method
19199      *      'responseError': function(rejection) {
19200      *         // do something on error
19201      *         if (canRecover(rejection)) {
19202      *           return responseOrNewPromise
19203      *         }
19204      *         return $q.reject(rejection);
19205      *       }
19206      *     };
19207      *   });
19208      *
19209      *   $httpProvider.interceptors.push('myHttpInterceptor');
19210      *
19211      *
19212      *   // alternatively, register the interceptor via an anonymous factory
19213      *   $httpProvider.interceptors.push(function($q, dependency1, dependency2) {
19214      *     return {
19215      *      'request': function(config) {
19216      *          // same as above
19217      *       },
19218      *
19219      *       'response': function(response) {
19220      *          // same as above
19221      *       }
19222      *     };
19223      *   });
19224      * ```
19225      *
19226      * ## Security Considerations
19227      *
19228      * When designing web applications, consider security threats from:
19229      *
19230      * - [JSON vulnerability](http://haacked.com/archive/2008/11/20/anatomy-of-a-subtle-json-vulnerability.aspx)
19231      * - [XSRF](http://en.wikipedia.org/wiki/Cross-site_request_forgery)
19232      *
19233      * Both server and the client must cooperate in order to eliminate these threats. Angular comes
19234      * pre-configured with strategies that address these issues, but for this to work backend server
19235      * cooperation is required.
19236      *
19237      * ### JSON Vulnerability Protection
19238      *
19239      * A [JSON vulnerability](http://haacked.com/archive/2008/11/20/anatomy-of-a-subtle-json-vulnerability.aspx)
19240      * allows third party website to turn your JSON resource URL into
19241      * [JSONP](http://en.wikipedia.org/wiki/JSONP) request under some conditions. To
19242      * counter this your server can prefix all JSON requests with following string `")]}',\n"`.
19243      * Angular will automatically strip the prefix before processing it as JSON.
19244      *
19245      * For example if your server needs to return:
19246      * ```js
19247      * ['one','two']
19248      * ```
19249      *
19250      * which is vulnerable to attack, your server can return:
19251      * ```js
19252      * )]}',
19253      * ['one','two']
19254      * ```
19255      *
19256      * Angular will strip the prefix, before processing the JSON.
19257      *
19258      *
19259      * ### Cross Site Request Forgery (XSRF) Protection
19260      *
19261      * [XSRF](http://en.wikipedia.org/wiki/Cross-site_request_forgery) is a technique by which
19262      * an unauthorized site can gain your user's private data. Angular provides a mechanism
19263      * to counter XSRF. When performing XHR requests, the $http service reads a token from a cookie
19264      * (by default, `XSRF-TOKEN`) and sets it as an HTTP header (`X-XSRF-TOKEN`). Since only
19265      * JavaScript that runs on your domain could read the cookie, your server can be assured that
19266      * the XHR came from JavaScript running on your domain. The header will not be set for
19267      * cross-domain requests.
19268      *
19269      * To take advantage of this, your server needs to set a token in a JavaScript readable session
19270      * cookie called `XSRF-TOKEN` on the first HTTP GET request. On subsequent XHR requests the
19271      * server can verify that the cookie matches `X-XSRF-TOKEN` HTTP header, and therefore be sure
19272      * that only JavaScript running on your domain could have sent the request. The token must be
19273      * unique for each user and must be verifiable by the server (to prevent the JavaScript from
19274      * making up its own tokens). We recommend that the token is a digest of your site's
19275      * authentication cookie with a [salt](https://en.wikipedia.org/wiki/Salt_(cryptography&#41;)
19276      * for added security.
19277      *
19278      * The name of the headers can be specified using the xsrfHeaderName and xsrfCookieName
19279      * properties of either $httpProvider.defaults at config-time, $http.defaults at run-time,
19280      * or the per-request config object.
19281      *
19282      * In order to prevent collisions in environments where multiple Angular apps share the
19283      * same domain or subdomain, we recommend that each application uses unique cookie name.
19284      *
19285      * @param {object} config Object describing the request to be made and how it should be
19286      *    processed. The object has following properties:
19287      *
19288      *    - **method** – `{string}` – HTTP method (e.g. 'GET', 'POST', etc)
19289      *    - **url** – `{string}` – Absolute or relative URL of the resource that is being requested.
19290      *    - **params** – `{Object.<string|Object>}` – Map of strings or objects which will be serialized
19291      *      with the `paramSerializer` and appended as GET parameters.
19292      *    - **data** – `{string|Object}` – Data to be sent as the request message data.
19293      *    - **headers** – `{Object}` – Map of strings or functions which return strings representing
19294      *      HTTP headers to send to the server. If the return value of a function is null, the
19295      *      header will not be sent. Functions accept a config object as an argument.
19296      *    - **xsrfHeaderName** – `{string}` – Name of HTTP header to populate with the XSRF token.
19297      *    - **xsrfCookieName** – `{string}` – Name of cookie containing the XSRF token.
19298      *    - **transformRequest** –
19299      *      `{function(data, headersGetter)|Array.<function(data, headersGetter)>}` –
19300      *      transform function or an array of such functions. The transform function takes the http
19301      *      request body and headers and returns its transformed (typically serialized) version.
19302      *      See {@link ng.$http#overriding-the-default-transformations-per-request
19303      *      Overriding the Default Transformations}
19304      *    - **transformResponse** –
19305      *      `{function(data, headersGetter, status)|Array.<function(data, headersGetter, status)>}` –
19306      *      transform function or an array of such functions. The transform function takes the http
19307      *      response body, headers and status and returns its transformed (typically deserialized) version.
19308      *      See {@link ng.$http#overriding-the-default-transformations-per-request
19309      *      Overriding the Default TransformationjqLiks}
19310      *    - **paramSerializer** - `{string|function(Object<string,string>):string}` - A function used to
19311      *      prepare the string representation of request parameters (specified as an object).
19312      *      If specified as string, it is interpreted as function registered with the
19313      *      {@link $injector $injector}, which means you can create your own serializer
19314      *      by registering it as a {@link auto.$provide#service service}.
19315      *      The default serializer is the {@link $httpParamSerializer $httpParamSerializer};
19316      *      alternatively, you can use the {@link $httpParamSerializerJQLike $httpParamSerializerJQLike}
19317      *    - **cache** – `{boolean|Cache}` – If true, a default $http cache will be used to cache the
19318      *      GET request, otherwise if a cache instance built with
19319      *      {@link ng.$cacheFactory $cacheFactory}, this cache will be used for
19320      *      caching.
19321      *    - **timeout** – `{number|Promise}` – timeout in milliseconds, or {@link ng.$q promise}
19322      *      that should abort the request when resolved.
19323      *    - **withCredentials** - `{boolean}` - whether to set the `withCredentials` flag on the
19324      *      XHR object. See [requests with credentials](https://developer.mozilla.org/docs/Web/HTTP/Access_control_CORS#Requests_with_credentials)
19325      *      for more information.
19326      *    - **responseType** - `{string}` - see
19327      *      [XMLHttpRequest.responseType](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest#xmlhttprequest-responsetype).
19328      *
19329      * @returns {HttpPromise} Returns a {@link ng.$q `Promise}` that will be resolved to a response object
19330      *                        when the request succeeds or fails.
19331      *
19332      *
19333      * @property {Array.<Object>} pendingRequests Array of config objects for currently pending
19334      *   requests. This is primarily meant to be used for debugging purposes.
19335      *
19336      *
19337      * @example
19338 <example module="httpExample">
19339 <file name="index.html">
19340   <div ng-controller="FetchController">
19341     <select ng-model="method" aria-label="Request method">
19342       <option>GET</option>
19343       <option>JSONP</option>
19344     </select>
19345     <input type="text" ng-model="url" size="80" aria-label="URL" />
19346     <button id="fetchbtn" ng-click="fetch()">fetch</button><br>
19347     <button id="samplegetbtn" ng-click="updateModel('GET', 'http-hello.html')">Sample GET</button>
19348     <button id="samplejsonpbtn"
19349       ng-click="updateModel('JSONP',
19350                     'https://angularjs.org/greet.php?callback=JSON_CALLBACK&name=Super%20Hero')">
19351       Sample JSONP
19352     </button>
19353     <button id="invalidjsonpbtn"
19354       ng-click="updateModel('JSONP', 'https://angularjs.org/doesntexist&callback=JSON_CALLBACK')">
19355         Invalid JSONP
19356       </button>
19357     <pre>http status code: {{status}}</pre>
19358     <pre>http response data: {{data}}</pre>
19359   </div>
19360 </file>
19361 <file name="script.js">
19362   angular.module('httpExample', [])
19363     .controller('FetchController', ['$scope', '$http', '$templateCache',
19364       function($scope, $http, $templateCache) {
19365         $scope.method = 'GET';
19366         $scope.url = 'http-hello.html';
19367
19368         $scope.fetch = function() {
19369           $scope.code = null;
19370           $scope.response = null;
19371
19372           $http({method: $scope.method, url: $scope.url, cache: $templateCache}).
19373             then(function(response) {
19374               $scope.status = response.status;
19375               $scope.data = response.data;
19376             }, function(response) {
19377               $scope.data = response.data || "Request failed";
19378               $scope.status = response.status;
19379           });
19380         };
19381
19382         $scope.updateModel = function(method, url) {
19383           $scope.method = method;
19384           $scope.url = url;
19385         };
19386       }]);
19387 </file>
19388 <file name="http-hello.html">
19389   Hello, $http!
19390 </file>
19391 <file name="protractor.js" type="protractor">
19392   var status = element(by.binding('status'));
19393   var data = element(by.binding('data'));
19394   var fetchBtn = element(by.id('fetchbtn'));
19395   var sampleGetBtn = element(by.id('samplegetbtn'));
19396   var sampleJsonpBtn = element(by.id('samplejsonpbtn'));
19397   var invalidJsonpBtn = element(by.id('invalidjsonpbtn'));
19398
19399   it('should make an xhr GET request', function() {
19400     sampleGetBtn.click();
19401     fetchBtn.click();
19402     expect(status.getText()).toMatch('200');
19403     expect(data.getText()).toMatch(/Hello, \$http!/);
19404   });
19405
19406 // Commented out due to flakes. See https://github.com/angular/angular.js/issues/9185
19407 // it('should make a JSONP request to angularjs.org', function() {
19408 //   sampleJsonpBtn.click();
19409 //   fetchBtn.click();
19410 //   expect(status.getText()).toMatch('200');
19411 //   expect(data.getText()).toMatch(/Super Hero!/);
19412 // });
19413
19414   it('should make JSONP request to invalid URL and invoke the error handler',
19415       function() {
19416     invalidJsonpBtn.click();
19417     fetchBtn.click();
19418     expect(status.getText()).toMatch('0');
19419     expect(data.getText()).toMatch('Request failed');
19420   });
19421 </file>
19422 </example>
19423      */
19424     function $http(requestConfig) {
19425
19426       if (!angular.isObject(requestConfig)) {
19427         throw minErr('$http')('badreq', 'Http request configuration must be an object.  Received: {0}', requestConfig);
19428       }
19429
19430       var config = extend({
19431         method: 'get',
19432         transformRequest: defaults.transformRequest,
19433         transformResponse: defaults.transformResponse,
19434         paramSerializer: defaults.paramSerializer
19435       }, requestConfig);
19436
19437       config.headers = mergeHeaders(requestConfig);
19438       config.method = uppercase(config.method);
19439       config.paramSerializer = isString(config.paramSerializer) ?
19440         $injector.get(config.paramSerializer) : config.paramSerializer;
19441
19442       var serverRequest = function(config) {
19443         var headers = config.headers;
19444         var reqData = transformData(config.data, headersGetter(headers), undefined, config.transformRequest);
19445
19446         // strip content-type if data is undefined
19447         if (isUndefined(reqData)) {
19448           forEach(headers, function(value, header) {
19449             if (lowercase(header) === 'content-type') {
19450                 delete headers[header];
19451             }
19452           });
19453         }
19454
19455         if (isUndefined(config.withCredentials) && !isUndefined(defaults.withCredentials)) {
19456           config.withCredentials = defaults.withCredentials;
19457         }
19458
19459         // send request
19460         return sendReq(config, reqData).then(transformResponse, transformResponse);
19461       };
19462
19463       var chain = [serverRequest, undefined];
19464       var promise = $q.when(config);
19465
19466       // apply interceptors
19467       forEach(reversedInterceptors, function(interceptor) {
19468         if (interceptor.request || interceptor.requestError) {
19469           chain.unshift(interceptor.request, interceptor.requestError);
19470         }
19471         if (interceptor.response || interceptor.responseError) {
19472           chain.push(interceptor.response, interceptor.responseError);
19473         }
19474       });
19475
19476       while (chain.length) {
19477         var thenFn = chain.shift();
19478         var rejectFn = chain.shift();
19479
19480         promise = promise.then(thenFn, rejectFn);
19481       }
19482
19483       if (useLegacyPromise) {
19484         promise.success = function(fn) {
19485           assertArgFn(fn, 'fn');
19486
19487           promise.then(function(response) {
19488             fn(response.data, response.status, response.headers, config);
19489           });
19490           return promise;
19491         };
19492
19493         promise.error = function(fn) {
19494           assertArgFn(fn, 'fn');
19495
19496           promise.then(null, function(response) {
19497             fn(response.data, response.status, response.headers, config);
19498           });
19499           return promise;
19500         };
19501       } else {
19502         promise.success = $httpMinErrLegacyFn('success');
19503         promise.error = $httpMinErrLegacyFn('error');
19504       }
19505
19506       return promise;
19507
19508       function transformResponse(response) {
19509         // make a copy since the response must be cacheable
19510         var resp = extend({}, response);
19511         resp.data = transformData(response.data, response.headers, response.status,
19512                                   config.transformResponse);
19513         return (isSuccess(response.status))
19514           ? resp
19515           : $q.reject(resp);
19516       }
19517
19518       function executeHeaderFns(headers, config) {
19519         var headerContent, processedHeaders = {};
19520
19521         forEach(headers, function(headerFn, header) {
19522           if (isFunction(headerFn)) {
19523             headerContent = headerFn(config);
19524             if (headerContent != null) {
19525               processedHeaders[header] = headerContent;
19526             }
19527           } else {
19528             processedHeaders[header] = headerFn;
19529           }
19530         });
19531
19532         return processedHeaders;
19533       }
19534
19535       function mergeHeaders(config) {
19536         var defHeaders = defaults.headers,
19537             reqHeaders = extend({}, config.headers),
19538             defHeaderName, lowercaseDefHeaderName, reqHeaderName;
19539
19540         defHeaders = extend({}, defHeaders.common, defHeaders[lowercase(config.method)]);
19541
19542         // using for-in instead of forEach to avoid unecessary iteration after header has been found
19543         defaultHeadersIteration:
19544         for (defHeaderName in defHeaders) {
19545           lowercaseDefHeaderName = lowercase(defHeaderName);
19546
19547           for (reqHeaderName in reqHeaders) {
19548             if (lowercase(reqHeaderName) === lowercaseDefHeaderName) {
19549               continue defaultHeadersIteration;
19550             }
19551           }
19552
19553           reqHeaders[defHeaderName] = defHeaders[defHeaderName];
19554         }
19555
19556         // execute if header value is a function for merged headers
19557         return executeHeaderFns(reqHeaders, shallowCopy(config));
19558       }
19559     }
19560
19561     $http.pendingRequests = [];
19562
19563     /**
19564      * @ngdoc method
19565      * @name $http#get
19566      *
19567      * @description
19568      * Shortcut method to perform `GET` request.
19569      *
19570      * @param {string} url Relative or absolute URL specifying the destination of the request
19571      * @param {Object=} config Optional configuration object
19572      * @returns {HttpPromise} Future object
19573      */
19574
19575     /**
19576      * @ngdoc method
19577      * @name $http#delete
19578      *
19579      * @description
19580      * Shortcut method to perform `DELETE` request.
19581      *
19582      * @param {string} url Relative or absolute URL specifying the destination of the request
19583      * @param {Object=} config Optional configuration object
19584      * @returns {HttpPromise} Future object
19585      */
19586
19587     /**
19588      * @ngdoc method
19589      * @name $http#head
19590      *
19591      * @description
19592      * Shortcut method to perform `HEAD` request.
19593      *
19594      * @param {string} url Relative or absolute URL specifying the destination of the request
19595      * @param {Object=} config Optional configuration object
19596      * @returns {HttpPromise} Future object
19597      */
19598
19599     /**
19600      * @ngdoc method
19601      * @name $http#jsonp
19602      *
19603      * @description
19604      * Shortcut method to perform `JSONP` request.
19605      *
19606      * @param {string} url Relative or absolute URL specifying the destination of the request.
19607      *                     The name of the callback should be the string `JSON_CALLBACK`.
19608      * @param {Object=} config Optional configuration object
19609      * @returns {HttpPromise} Future object
19610      */
19611     createShortMethods('get', 'delete', 'head', 'jsonp');
19612
19613     /**
19614      * @ngdoc method
19615      * @name $http#post
19616      *
19617      * @description
19618      * Shortcut method to perform `POST` request.
19619      *
19620      * @param {string} url Relative or absolute URL specifying the destination of the request
19621      * @param {*} data Request content
19622      * @param {Object=} config Optional configuration object
19623      * @returns {HttpPromise} Future object
19624      */
19625
19626     /**
19627      * @ngdoc method
19628      * @name $http#put
19629      *
19630      * @description
19631      * Shortcut method to perform `PUT` request.
19632      *
19633      * @param {string} url Relative or absolute URL specifying the destination of the request
19634      * @param {*} data Request content
19635      * @param {Object=} config Optional configuration object
19636      * @returns {HttpPromise} Future object
19637      */
19638
19639      /**
19640       * @ngdoc method
19641       * @name $http#patch
19642       *
19643       * @description
19644       * Shortcut method to perform `PATCH` request.
19645       *
19646       * @param {string} url Relative or absolute URL specifying the destination of the request
19647       * @param {*} data Request content
19648       * @param {Object=} config Optional configuration object
19649       * @returns {HttpPromise} Future object
19650       */
19651     createShortMethodsWithData('post', 'put', 'patch');
19652
19653         /**
19654          * @ngdoc property
19655          * @name $http#defaults
19656          *
19657          * @description
19658          * Runtime equivalent of the `$httpProvider.defaults` property. Allows configuration of
19659          * default headers, withCredentials as well as request and response transformations.
19660          *
19661          * See "Setting HTTP Headers" and "Transforming Requests and Responses" sections above.
19662          */
19663     $http.defaults = defaults;
19664
19665
19666     return $http;
19667
19668
19669     function createShortMethods(names) {
19670       forEach(arguments, function(name) {
19671         $http[name] = function(url, config) {
19672           return $http(extend({}, config || {}, {
19673             method: name,
19674             url: url
19675           }));
19676         };
19677       });
19678     }
19679
19680
19681     function createShortMethodsWithData(name) {
19682       forEach(arguments, function(name) {
19683         $http[name] = function(url, data, config) {
19684           return $http(extend({}, config || {}, {
19685             method: name,
19686             url: url,
19687             data: data
19688           }));
19689         };
19690       });
19691     }
19692
19693
19694     /**
19695      * Makes the request.
19696      *
19697      * !!! ACCESSES CLOSURE VARS:
19698      * $httpBackend, defaults, $log, $rootScope, defaultCache, $http.pendingRequests
19699      */
19700     function sendReq(config, reqData) {
19701       var deferred = $q.defer(),
19702           promise = deferred.promise,
19703           cache,
19704           cachedResp,
19705           reqHeaders = config.headers,
19706           url = buildUrl(config.url, config.paramSerializer(config.params));
19707
19708       $http.pendingRequests.push(config);
19709       promise.then(removePendingReq, removePendingReq);
19710
19711
19712       if ((config.cache || defaults.cache) && config.cache !== false &&
19713           (config.method === 'GET' || config.method === 'JSONP')) {
19714         cache = isObject(config.cache) ? config.cache
19715               : isObject(defaults.cache) ? defaults.cache
19716               : defaultCache;
19717       }
19718
19719       if (cache) {
19720         cachedResp = cache.get(url);
19721         if (isDefined(cachedResp)) {
19722           if (isPromiseLike(cachedResp)) {
19723             // cached request has already been sent, but there is no response yet
19724             cachedResp.then(resolvePromiseWithResult, resolvePromiseWithResult);
19725           } else {
19726             // serving from cache
19727             if (isArray(cachedResp)) {
19728               resolvePromise(cachedResp[1], cachedResp[0], shallowCopy(cachedResp[2]), cachedResp[3]);
19729             } else {
19730               resolvePromise(cachedResp, 200, {}, 'OK');
19731             }
19732           }
19733         } else {
19734           // put the promise for the non-transformed response into cache as a placeholder
19735           cache.put(url, promise);
19736         }
19737       }
19738
19739
19740       // if we won't have the response in cache, set the xsrf headers and
19741       // send the request to the backend
19742       if (isUndefined(cachedResp)) {
19743         var xsrfValue = urlIsSameOrigin(config.url)
19744             ? $$cookieReader()[config.xsrfCookieName || defaults.xsrfCookieName]
19745             : undefined;
19746         if (xsrfValue) {
19747           reqHeaders[(config.xsrfHeaderName || defaults.xsrfHeaderName)] = xsrfValue;
19748         }
19749
19750         $httpBackend(config.method, url, reqData, done, reqHeaders, config.timeout,
19751             config.withCredentials, config.responseType);
19752       }
19753
19754       return promise;
19755
19756
19757       /**
19758        * Callback registered to $httpBackend():
19759        *  - caches the response if desired
19760        *  - resolves the raw $http promise
19761        *  - calls $apply
19762        */
19763       function done(status, response, headersString, statusText) {
19764         if (cache) {
19765           if (isSuccess(status)) {
19766             cache.put(url, [status, response, parseHeaders(headersString), statusText]);
19767           } else {
19768             // remove promise from the cache
19769             cache.remove(url);
19770           }
19771         }
19772
19773         function resolveHttpPromise() {
19774           resolvePromise(response, status, headersString, statusText);
19775         }
19776
19777         if (useApplyAsync) {
19778           $rootScope.$applyAsync(resolveHttpPromise);
19779         } else {
19780           resolveHttpPromise();
19781           if (!$rootScope.$$phase) $rootScope.$apply();
19782         }
19783       }
19784
19785
19786       /**
19787        * Resolves the raw $http promise.
19788        */
19789       function resolvePromise(response, status, headers, statusText) {
19790         //status: HTTP response status code, 0, -1 (aborted by timeout / promise)
19791         status = status >= -1 ? status : 0;
19792
19793         (isSuccess(status) ? deferred.resolve : deferred.reject)({
19794           data: response,
19795           status: status,
19796           headers: headersGetter(headers),
19797           config: config,
19798           statusText: statusText
19799         });
19800       }
19801
19802       function resolvePromiseWithResult(result) {
19803         resolvePromise(result.data, result.status, shallowCopy(result.headers()), result.statusText);
19804       }
19805
19806       function removePendingReq() {
19807         var idx = $http.pendingRequests.indexOf(config);
19808         if (idx !== -1) $http.pendingRequests.splice(idx, 1);
19809       }
19810     }
19811
19812
19813     function buildUrl(url, serializedParams) {
19814       if (serializedParams.length > 0) {
19815         url += ((url.indexOf('?') == -1) ? '?' : '&') + serializedParams;
19816       }
19817       return url;
19818     }
19819   }];
19820 }
19821
19822 /**
19823  * @ngdoc service
19824  * @name $xhrFactory
19825  *
19826  * @description
19827  * Factory function used to create XMLHttpRequest objects.
19828  *
19829  * Replace or decorate this service to create your own custom XMLHttpRequest objects.
19830  *
19831  * ```
19832  * angular.module('myApp', [])
19833  * .factory('$xhrFactory', function() {
19834  *   return function createXhr(method, url) {
19835  *     return new window.XMLHttpRequest({mozSystem: true});
19836  *   };
19837  * });
19838  * ```
19839  *
19840  * @param {string} method HTTP method of the request (GET, POST, PUT, ..)
19841  * @param {string} url URL of the request.
19842  */
19843 function $xhrFactoryProvider() {
19844   this.$get = function() {
19845     return function createXhr() {
19846       return new window.XMLHttpRequest();
19847     };
19848   };
19849 }
19850
19851 /**
19852  * @ngdoc service
19853  * @name $httpBackend
19854  * @requires $window
19855  * @requires $document
19856  * @requires $xhrFactory
19857  *
19858  * @description
19859  * HTTP backend used by the {@link ng.$http service} that delegates to
19860  * XMLHttpRequest object or JSONP and deals with browser incompatibilities.
19861  *
19862  * You should never need to use this service directly, instead use the higher-level abstractions:
19863  * {@link ng.$http $http} or {@link ngResource.$resource $resource}.
19864  *
19865  * During testing this implementation is swapped with {@link ngMock.$httpBackend mock
19866  * $httpBackend} which can be trained with responses.
19867  */
19868 function $HttpBackendProvider() {
19869   this.$get = ['$browser', '$window', '$document', '$xhrFactory', function($browser, $window, $document, $xhrFactory) {
19870     return createHttpBackend($browser, $xhrFactory, $browser.defer, $window.angular.callbacks, $document[0]);
19871   }];
19872 }
19873
19874 function createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDocument) {
19875   // TODO(vojta): fix the signature
19876   return function(method, url, post, callback, headers, timeout, withCredentials, responseType) {
19877     $browser.$$incOutstandingRequestCount();
19878     url = url || $browser.url();
19879
19880     if (lowercase(method) == 'jsonp') {
19881       var callbackId = '_' + (callbacks.counter++).toString(36);
19882       callbacks[callbackId] = function(data) {
19883         callbacks[callbackId].data = data;
19884         callbacks[callbackId].called = true;
19885       };
19886
19887       var jsonpDone = jsonpReq(url.replace('JSON_CALLBACK', 'angular.callbacks.' + callbackId),
19888           callbackId, function(status, text) {
19889         completeRequest(callback, status, callbacks[callbackId].data, "", text);
19890         callbacks[callbackId] = noop;
19891       });
19892     } else {
19893
19894       var xhr = createXhr(method, url);
19895
19896       xhr.open(method, url, true);
19897       forEach(headers, function(value, key) {
19898         if (isDefined(value)) {
19899             xhr.setRequestHeader(key, value);
19900         }
19901       });
19902
19903       xhr.onload = function requestLoaded() {
19904         var statusText = xhr.statusText || '';
19905
19906         // responseText is the old-school way of retrieving response (supported by IE9)
19907         // response/responseType properties were introduced in XHR Level2 spec (supported by IE10)
19908         var response = ('response' in xhr) ? xhr.response : xhr.responseText;
19909
19910         // normalize IE9 bug (http://bugs.jquery.com/ticket/1450)
19911         var status = xhr.status === 1223 ? 204 : xhr.status;
19912
19913         // fix status code when it is 0 (0 status is undocumented).
19914         // Occurs when accessing file resources or on Android 4.1 stock browser
19915         // while retrieving files from application cache.
19916         if (status === 0) {
19917           status = response ? 200 : urlResolve(url).protocol == 'file' ? 404 : 0;
19918         }
19919
19920         completeRequest(callback,
19921             status,
19922             response,
19923             xhr.getAllResponseHeaders(),
19924             statusText);
19925       };
19926
19927       var requestError = function() {
19928         // The response is always empty
19929         // See https://xhr.spec.whatwg.org/#request-error-steps and https://fetch.spec.whatwg.org/#concept-network-error
19930         completeRequest(callback, -1, null, null, '');
19931       };
19932
19933       xhr.onerror = requestError;
19934       xhr.onabort = requestError;
19935
19936       if (withCredentials) {
19937         xhr.withCredentials = true;
19938       }
19939
19940       if (responseType) {
19941         try {
19942           xhr.responseType = responseType;
19943         } catch (e) {
19944           // WebKit added support for the json responseType value on 09/03/2013
19945           // https://bugs.webkit.org/show_bug.cgi?id=73648. Versions of Safari prior to 7 are
19946           // known to throw when setting the value "json" as the response type. Other older
19947           // browsers implementing the responseType
19948           //
19949           // The json response type can be ignored if not supported, because JSON payloads are
19950           // parsed on the client-side regardless.
19951           if (responseType !== 'json') {
19952             throw e;
19953           }
19954         }
19955       }
19956
19957       xhr.send(isUndefined(post) ? null : post);
19958     }
19959
19960     if (timeout > 0) {
19961       var timeoutId = $browserDefer(timeoutRequest, timeout);
19962     } else if (isPromiseLike(timeout)) {
19963       timeout.then(timeoutRequest);
19964     }
19965
19966
19967     function timeoutRequest() {
19968       jsonpDone && jsonpDone();
19969       xhr && xhr.abort();
19970     }
19971
19972     function completeRequest(callback, status, response, headersString, statusText) {
19973       // cancel timeout and subsequent timeout promise resolution
19974       if (isDefined(timeoutId)) {
19975         $browserDefer.cancel(timeoutId);
19976       }
19977       jsonpDone = xhr = null;
19978
19979       callback(status, response, headersString, statusText);
19980       $browser.$$completeOutstandingRequest(noop);
19981     }
19982   };
19983
19984   function jsonpReq(url, callbackId, done) {
19985     // we can't use jQuery/jqLite here because jQuery does crazy stuff with script elements, e.g.:
19986     // - fetches local scripts via XHR and evals them
19987     // - adds and immediately removes script elements from the document
19988     var script = rawDocument.createElement('script'), callback = null;
19989     script.type = "text/javascript";
19990     script.src = url;
19991     script.async = true;
19992
19993     callback = function(event) {
19994       removeEventListenerFn(script, "load", callback);
19995       removeEventListenerFn(script, "error", callback);
19996       rawDocument.body.removeChild(script);
19997       script = null;
19998       var status = -1;
19999       var text = "unknown";
20000
20001       if (event) {
20002         if (event.type === "load" && !callbacks[callbackId].called) {
20003           event = { type: "error" };
20004         }
20005         text = event.type;
20006         status = event.type === "error" ? 404 : 200;
20007       }
20008
20009       if (done) {
20010         done(status, text);
20011       }
20012     };
20013
20014     addEventListenerFn(script, "load", callback);
20015     addEventListenerFn(script, "error", callback);
20016     rawDocument.body.appendChild(script);
20017     return callback;
20018   }
20019 }
20020
20021 var $interpolateMinErr = angular.$interpolateMinErr = minErr('$interpolate');
20022 $interpolateMinErr.throwNoconcat = function(text) {
20023   throw $interpolateMinErr('noconcat',
20024       "Error while interpolating: {0}\nStrict Contextual Escaping disallows " +
20025       "interpolations that concatenate multiple expressions when a trusted value is " +
20026       "required.  See http://docs.angularjs.org/api/ng.$sce", text);
20027 };
20028
20029 $interpolateMinErr.interr = function(text, err) {
20030   return $interpolateMinErr('interr', "Can't interpolate: {0}\n{1}", text, err.toString());
20031 };
20032
20033 /**
20034  * @ngdoc provider
20035  * @name $interpolateProvider
20036  *
20037  * @description
20038  *
20039  * Used for configuring the interpolation markup. Defaults to `{{` and `}}`.
20040  *
20041  * @example
20042 <example module="customInterpolationApp">
20043 <file name="index.html">
20044 <script>
20045   var customInterpolationApp = angular.module('customInterpolationApp', []);
20046
20047   customInterpolationApp.config(function($interpolateProvider) {
20048     $interpolateProvider.startSymbol('//');
20049     $interpolateProvider.endSymbol('//');
20050   });
20051
20052
20053   customInterpolationApp.controller('DemoController', function() {
20054       this.label = "This binding is brought you by // interpolation symbols.";
20055   });
20056 </script>
20057 <div ng-app="App" ng-controller="DemoController as demo">
20058     //demo.label//
20059 </div>
20060 </file>
20061 <file name="protractor.js" type="protractor">
20062   it('should interpolate binding with custom symbols', function() {
20063     expect(element(by.binding('demo.label')).getText()).toBe('This binding is brought you by // interpolation symbols.');
20064   });
20065 </file>
20066 </example>
20067  */
20068 function $InterpolateProvider() {
20069   var startSymbol = '{{';
20070   var endSymbol = '}}';
20071
20072   /**
20073    * @ngdoc method
20074    * @name $interpolateProvider#startSymbol
20075    * @description
20076    * Symbol to denote start of expression in the interpolated string. Defaults to `{{`.
20077    *
20078    * @param {string=} value new value to set the starting symbol to.
20079    * @returns {string|self} Returns the symbol when used as getter and self if used as setter.
20080    */
20081   this.startSymbol = function(value) {
20082     if (value) {
20083       startSymbol = value;
20084       return this;
20085     } else {
20086       return startSymbol;
20087     }
20088   };
20089
20090   /**
20091    * @ngdoc method
20092    * @name $interpolateProvider#endSymbol
20093    * @description
20094    * Symbol to denote the end of expression in the interpolated string. Defaults to `}}`.
20095    *
20096    * @param {string=} value new value to set the ending symbol to.
20097    * @returns {string|self} Returns the symbol when used as getter and self if used as setter.
20098    */
20099   this.endSymbol = function(value) {
20100     if (value) {
20101       endSymbol = value;
20102       return this;
20103     } else {
20104       return endSymbol;
20105     }
20106   };
20107
20108
20109   this.$get = ['$parse', '$exceptionHandler', '$sce', function($parse, $exceptionHandler, $sce) {
20110     var startSymbolLength = startSymbol.length,
20111         endSymbolLength = endSymbol.length,
20112         escapedStartRegexp = new RegExp(startSymbol.replace(/./g, escape), 'g'),
20113         escapedEndRegexp = new RegExp(endSymbol.replace(/./g, escape), 'g');
20114
20115     function escape(ch) {
20116       return '\\\\\\' + ch;
20117     }
20118
20119     function unescapeText(text) {
20120       return text.replace(escapedStartRegexp, startSymbol).
20121         replace(escapedEndRegexp, endSymbol);
20122     }
20123
20124     function stringify(value) {
20125       if (value == null) { // null || undefined
20126         return '';
20127       }
20128       switch (typeof value) {
20129         case 'string':
20130           break;
20131         case 'number':
20132           value = '' + value;
20133           break;
20134         default:
20135           value = toJson(value);
20136       }
20137
20138       return value;
20139     }
20140
20141     /**
20142      * @ngdoc service
20143      * @name $interpolate
20144      * @kind function
20145      *
20146      * @requires $parse
20147      * @requires $sce
20148      *
20149      * @description
20150      *
20151      * Compiles a string with markup into an interpolation function. This service is used by the
20152      * HTML {@link ng.$compile $compile} service for data binding. See
20153      * {@link ng.$interpolateProvider $interpolateProvider} for configuring the
20154      * interpolation markup.
20155      *
20156      *
20157      * ```js
20158      *   var $interpolate = ...; // injected
20159      *   var exp = $interpolate('Hello {{name | uppercase}}!');
20160      *   expect(exp({name:'Angular'})).toEqual('Hello ANGULAR!');
20161      * ```
20162      *
20163      * `$interpolate` takes an optional fourth argument, `allOrNothing`. If `allOrNothing` is
20164      * `true`, the interpolation function will return `undefined` unless all embedded expressions
20165      * evaluate to a value other than `undefined`.
20166      *
20167      * ```js
20168      *   var $interpolate = ...; // injected
20169      *   var context = {greeting: 'Hello', name: undefined };
20170      *
20171      *   // default "forgiving" mode
20172      *   var exp = $interpolate('{{greeting}} {{name}}!');
20173      *   expect(exp(context)).toEqual('Hello !');
20174      *
20175      *   // "allOrNothing" mode
20176      *   exp = $interpolate('{{greeting}} {{name}}!', false, null, true);
20177      *   expect(exp(context)).toBeUndefined();
20178      *   context.name = 'Angular';
20179      *   expect(exp(context)).toEqual('Hello Angular!');
20180      * ```
20181      *
20182      * `allOrNothing` is useful for interpolating URLs. `ngSrc` and `ngSrcset` use this behavior.
20183      *
20184      * ####Escaped Interpolation
20185      * $interpolate provides a mechanism for escaping interpolation markers. Start and end markers
20186      * can be escaped by preceding each of their characters with a REVERSE SOLIDUS U+005C (backslash).
20187      * It will be rendered as a regular start/end marker, and will not be interpreted as an expression
20188      * or binding.
20189      *
20190      * This enables web-servers to prevent script injection attacks and defacing attacks, to some
20191      * degree, while also enabling code examples to work without relying on the
20192      * {@link ng.directive:ngNonBindable ngNonBindable} directive.
20193      *
20194      * **For security purposes, it is strongly encouraged that web servers escape user-supplied data,
20195      * replacing angle brackets (&lt;, &gt;) with &amp;lt; and &amp;gt; respectively, and replacing all
20196      * interpolation start/end markers with their escaped counterparts.**
20197      *
20198      * Escaped interpolation markers are only replaced with the actual interpolation markers in rendered
20199      * output when the $interpolate service processes the text. So, for HTML elements interpolated
20200      * by {@link ng.$compile $compile}, or otherwise interpolated with the `mustHaveExpression` parameter
20201      * set to `true`, the interpolated text must contain an unescaped interpolation expression. As such,
20202      * this is typically useful only when user-data is used in rendering a template from the server, or
20203      * when otherwise untrusted data is used by a directive.
20204      *
20205      * <example>
20206      *  <file name="index.html">
20207      *    <div ng-init="username='A user'">
20208      *      <p ng-init="apptitle='Escaping demo'">{{apptitle}}: \{\{ username = "defaced value"; \}\}
20209      *        </p>
20210      *      <p><strong>{{username}}</strong> attempts to inject code which will deface the
20211      *        application, but fails to accomplish their task, because the server has correctly
20212      *        escaped the interpolation start/end markers with REVERSE SOLIDUS U+005C (backslash)
20213      *        characters.</p>
20214      *      <p>Instead, the result of the attempted script injection is visible, and can be removed
20215      *        from the database by an administrator.</p>
20216      *    </div>
20217      *  </file>
20218      * </example>
20219      *
20220      * @param {string} text The text with markup to interpolate.
20221      * @param {boolean=} mustHaveExpression if set to true then the interpolation string must have
20222      *    embedded expression in order to return an interpolation function. Strings with no
20223      *    embedded expression will return null for the interpolation function.
20224      * @param {string=} trustedContext when provided, the returned function passes the interpolated
20225      *    result through {@link ng.$sce#getTrusted $sce.getTrusted(interpolatedResult,
20226      *    trustedContext)} before returning it.  Refer to the {@link ng.$sce $sce} service that
20227      *    provides Strict Contextual Escaping for details.
20228      * @param {boolean=} allOrNothing if `true`, then the returned function returns undefined
20229      *    unless all embedded expressions evaluate to a value other than `undefined`.
20230      * @returns {function(context)} an interpolation function which is used to compute the
20231      *    interpolated string. The function has these parameters:
20232      *
20233      * - `context`: evaluation context for all expressions embedded in the interpolated text
20234      */
20235     function $interpolate(text, mustHaveExpression, trustedContext, allOrNothing) {
20236       allOrNothing = !!allOrNothing;
20237       var startIndex,
20238           endIndex,
20239           index = 0,
20240           expressions = [],
20241           parseFns = [],
20242           textLength = text.length,
20243           exp,
20244           concat = [],
20245           expressionPositions = [];
20246
20247       while (index < textLength) {
20248         if (((startIndex = text.indexOf(startSymbol, index)) != -1) &&
20249              ((endIndex = text.indexOf(endSymbol, startIndex + startSymbolLength)) != -1)) {
20250           if (index !== startIndex) {
20251             concat.push(unescapeText(text.substring(index, startIndex)));
20252           }
20253           exp = text.substring(startIndex + startSymbolLength, endIndex);
20254           expressions.push(exp);
20255           parseFns.push($parse(exp, parseStringifyInterceptor));
20256           index = endIndex + endSymbolLength;
20257           expressionPositions.push(concat.length);
20258           concat.push('');
20259         } else {
20260           // we did not find an interpolation, so we have to add the remainder to the separators array
20261           if (index !== textLength) {
20262             concat.push(unescapeText(text.substring(index)));
20263           }
20264           break;
20265         }
20266       }
20267
20268       // Concatenating expressions makes it hard to reason about whether some combination of
20269       // concatenated values are unsafe to use and could easily lead to XSS.  By requiring that a
20270       // single expression be used for iframe[src], object[src], etc., we ensure that the value
20271       // that's used is assigned or constructed by some JS code somewhere that is more testable or
20272       // make it obvious that you bound the value to some user controlled value.  This helps reduce
20273       // the load when auditing for XSS issues.
20274       if (trustedContext && concat.length > 1) {
20275           $interpolateMinErr.throwNoconcat(text);
20276       }
20277
20278       if (!mustHaveExpression || expressions.length) {
20279         var compute = function(values) {
20280           for (var i = 0, ii = expressions.length; i < ii; i++) {
20281             if (allOrNothing && isUndefined(values[i])) return;
20282             concat[expressionPositions[i]] = values[i];
20283           }
20284           return concat.join('');
20285         };
20286
20287         var getValue = function(value) {
20288           return trustedContext ?
20289             $sce.getTrusted(trustedContext, value) :
20290             $sce.valueOf(value);
20291         };
20292
20293         return extend(function interpolationFn(context) {
20294             var i = 0;
20295             var ii = expressions.length;
20296             var values = new Array(ii);
20297
20298             try {
20299               for (; i < ii; i++) {
20300                 values[i] = parseFns[i](context);
20301               }
20302
20303               return compute(values);
20304             } catch (err) {
20305               $exceptionHandler($interpolateMinErr.interr(text, err));
20306             }
20307
20308           }, {
20309           // all of these properties are undocumented for now
20310           exp: text, //just for compatibility with regular watchers created via $watch
20311           expressions: expressions,
20312           $$watchDelegate: function(scope, listener) {
20313             var lastValue;
20314             return scope.$watchGroup(parseFns, function interpolateFnWatcher(values, oldValues) {
20315               var currValue = compute(values);
20316               if (isFunction(listener)) {
20317                 listener.call(this, currValue, values !== oldValues ? lastValue : currValue, scope);
20318               }
20319               lastValue = currValue;
20320             });
20321           }
20322         });
20323       }
20324
20325       function parseStringifyInterceptor(value) {
20326         try {
20327           value = getValue(value);
20328           return allOrNothing && !isDefined(value) ? value : stringify(value);
20329         } catch (err) {
20330           $exceptionHandler($interpolateMinErr.interr(text, err));
20331         }
20332       }
20333     }
20334
20335
20336     /**
20337      * @ngdoc method
20338      * @name $interpolate#startSymbol
20339      * @description
20340      * Symbol to denote the start of expression in the interpolated string. Defaults to `{{`.
20341      *
20342      * Use {@link ng.$interpolateProvider#startSymbol `$interpolateProvider.startSymbol`} to change
20343      * the symbol.
20344      *
20345      * @returns {string} start symbol.
20346      */
20347     $interpolate.startSymbol = function() {
20348       return startSymbol;
20349     };
20350
20351
20352     /**
20353      * @ngdoc method
20354      * @name $interpolate#endSymbol
20355      * @description
20356      * Symbol to denote the end of expression in the interpolated string. Defaults to `}}`.
20357      *
20358      * Use {@link ng.$interpolateProvider#endSymbol `$interpolateProvider.endSymbol`} to change
20359      * the symbol.
20360      *
20361      * @returns {string} end symbol.
20362      */
20363     $interpolate.endSymbol = function() {
20364       return endSymbol;
20365     };
20366
20367     return $interpolate;
20368   }];
20369 }
20370
20371 function $IntervalProvider() {
20372   this.$get = ['$rootScope', '$window', '$q', '$$q',
20373        function($rootScope,   $window,   $q,   $$q) {
20374     var intervals = {};
20375
20376
20377      /**
20378       * @ngdoc service
20379       * @name $interval
20380       *
20381       * @description
20382       * Angular's wrapper for `window.setInterval`. The `fn` function is executed every `delay`
20383       * milliseconds.
20384       *
20385       * The return value of registering an interval function is a promise. This promise will be
20386       * notified upon each tick of the interval, and will be resolved after `count` iterations, or
20387       * run indefinitely if `count` is not defined. The value of the notification will be the
20388       * number of iterations that have run.
20389       * To cancel an interval, call `$interval.cancel(promise)`.
20390       *
20391       * In tests you can use {@link ngMock.$interval#flush `$interval.flush(millis)`} to
20392       * move forward by `millis` milliseconds and trigger any functions scheduled to run in that
20393       * time.
20394       *
20395       * <div class="alert alert-warning">
20396       * **Note**: Intervals created by this service must be explicitly destroyed when you are finished
20397       * with them.  In particular they are not automatically destroyed when a controller's scope or a
20398       * directive's element are destroyed.
20399       * You should take this into consideration and make sure to always cancel the interval at the
20400       * appropriate moment.  See the example below for more details on how and when to do this.
20401       * </div>
20402       *
20403       * @param {function()} fn A function that should be called repeatedly.
20404       * @param {number} delay Number of milliseconds between each function call.
20405       * @param {number=} [count=0] Number of times to repeat. If not set, or 0, will repeat
20406       *   indefinitely.
20407       * @param {boolean=} [invokeApply=true] If set to `false` skips model dirty checking, otherwise
20408       *   will invoke `fn` within the {@link ng.$rootScope.Scope#$apply $apply} block.
20409       * @param {...*=} Pass additional parameters to the executed function.
20410       * @returns {promise} A promise which will be notified on each iteration.
20411       *
20412       * @example
20413       * <example module="intervalExample">
20414       * <file name="index.html">
20415       *   <script>
20416       *     angular.module('intervalExample', [])
20417       *       .controller('ExampleController', ['$scope', '$interval',
20418       *         function($scope, $interval) {
20419       *           $scope.format = 'M/d/yy h:mm:ss a';
20420       *           $scope.blood_1 = 100;
20421       *           $scope.blood_2 = 120;
20422       *
20423       *           var stop;
20424       *           $scope.fight = function() {
20425       *             // Don't start a new fight if we are already fighting
20426       *             if ( angular.isDefined(stop) ) return;
20427       *
20428       *             stop = $interval(function() {
20429       *               if ($scope.blood_1 > 0 && $scope.blood_2 > 0) {
20430       *                 $scope.blood_1 = $scope.blood_1 - 3;
20431       *                 $scope.blood_2 = $scope.blood_2 - 4;
20432       *               } else {
20433       *                 $scope.stopFight();
20434       *               }
20435       *             }, 100);
20436       *           };
20437       *
20438       *           $scope.stopFight = function() {
20439       *             if (angular.isDefined(stop)) {
20440       *               $interval.cancel(stop);
20441       *               stop = undefined;
20442       *             }
20443       *           };
20444       *
20445       *           $scope.resetFight = function() {
20446       *             $scope.blood_1 = 100;
20447       *             $scope.blood_2 = 120;
20448       *           };
20449       *
20450       *           $scope.$on('$destroy', function() {
20451       *             // Make sure that the interval is destroyed too
20452       *             $scope.stopFight();
20453       *           });
20454       *         }])
20455       *       // Register the 'myCurrentTime' directive factory method.
20456       *       // We inject $interval and dateFilter service since the factory method is DI.
20457       *       .directive('myCurrentTime', ['$interval', 'dateFilter',
20458       *         function($interval, dateFilter) {
20459       *           // return the directive link function. (compile function not needed)
20460       *           return function(scope, element, attrs) {
20461       *             var format,  // date format
20462       *                 stopTime; // so that we can cancel the time updates
20463       *
20464       *             // used to update the UI
20465       *             function updateTime() {
20466       *               element.text(dateFilter(new Date(), format));
20467       *             }
20468       *
20469       *             // watch the expression, and update the UI on change.
20470       *             scope.$watch(attrs.myCurrentTime, function(value) {
20471       *               format = value;
20472       *               updateTime();
20473       *             });
20474       *
20475       *             stopTime = $interval(updateTime, 1000);
20476       *
20477       *             // listen on DOM destroy (removal) event, and cancel the next UI update
20478       *             // to prevent updating time after the DOM element was removed.
20479       *             element.on('$destroy', function() {
20480       *               $interval.cancel(stopTime);
20481       *             });
20482       *           }
20483       *         }]);
20484       *   </script>
20485       *
20486       *   <div>
20487       *     <div ng-controller="ExampleController">
20488       *       <label>Date format: <input ng-model="format"></label> <hr/>
20489       *       Current time is: <span my-current-time="format"></span>
20490       *       <hr/>
20491       *       Blood 1 : <font color='red'>{{blood_1}}</font>
20492       *       Blood 2 : <font color='red'>{{blood_2}}</font>
20493       *       <button type="button" data-ng-click="fight()">Fight</button>
20494       *       <button type="button" data-ng-click="stopFight()">StopFight</button>
20495       *       <button type="button" data-ng-click="resetFight()">resetFight</button>
20496       *     </div>
20497       *   </div>
20498       *
20499       * </file>
20500       * </example>
20501       */
20502     function interval(fn, delay, count, invokeApply) {
20503       var hasParams = arguments.length > 4,
20504           args = hasParams ? sliceArgs(arguments, 4) : [],
20505           setInterval = $window.setInterval,
20506           clearInterval = $window.clearInterval,
20507           iteration = 0,
20508           skipApply = (isDefined(invokeApply) && !invokeApply),
20509           deferred = (skipApply ? $$q : $q).defer(),
20510           promise = deferred.promise;
20511
20512       count = isDefined(count) ? count : 0;
20513
20514       promise.then(null, null, (!hasParams) ? fn : function() {
20515         fn.apply(null, args);
20516       });
20517
20518       promise.$$intervalId = setInterval(function tick() {
20519         deferred.notify(iteration++);
20520
20521         if (count > 0 && iteration >= count) {
20522           deferred.resolve(iteration);
20523           clearInterval(promise.$$intervalId);
20524           delete intervals[promise.$$intervalId];
20525         }
20526
20527         if (!skipApply) $rootScope.$apply();
20528
20529       }, delay);
20530
20531       intervals[promise.$$intervalId] = deferred;
20532
20533       return promise;
20534     }
20535
20536
20537      /**
20538       * @ngdoc method
20539       * @name $interval#cancel
20540       *
20541       * @description
20542       * Cancels a task associated with the `promise`.
20543       *
20544       * @param {Promise=} promise returned by the `$interval` function.
20545       * @returns {boolean} Returns `true` if the task was successfully canceled.
20546       */
20547     interval.cancel = function(promise) {
20548       if (promise && promise.$$intervalId in intervals) {
20549         intervals[promise.$$intervalId].reject('canceled');
20550         $window.clearInterval(promise.$$intervalId);
20551         delete intervals[promise.$$intervalId];
20552         return true;
20553       }
20554       return false;
20555     };
20556
20557     return interval;
20558   }];
20559 }
20560
20561 /**
20562  * @ngdoc service
20563  * @name $locale
20564  *
20565  * @description
20566  * $locale service provides localization rules for various Angular components. As of right now the
20567  * only public api is:
20568  *
20569  * * `id` – `{string}` – locale id formatted as `languageId-countryId` (e.g. `en-us`)
20570  */
20571
20572 var PATH_MATCH = /^([^\?#]*)(\?([^#]*))?(#(.*))?$/,
20573     DEFAULT_PORTS = {'http': 80, 'https': 443, 'ftp': 21};
20574 var $locationMinErr = minErr('$location');
20575
20576
20577 /**
20578  * Encode path using encodeUriSegment, ignoring forward slashes
20579  *
20580  * @param {string} path Path to encode
20581  * @returns {string}
20582  */
20583 function encodePath(path) {
20584   var segments = path.split('/'),
20585       i = segments.length;
20586
20587   while (i--) {
20588     segments[i] = encodeUriSegment(segments[i]);
20589   }
20590
20591   return segments.join('/');
20592 }
20593
20594 function parseAbsoluteUrl(absoluteUrl, locationObj) {
20595   var parsedUrl = urlResolve(absoluteUrl);
20596
20597   locationObj.$$protocol = parsedUrl.protocol;
20598   locationObj.$$host = parsedUrl.hostname;
20599   locationObj.$$port = toInt(parsedUrl.port) || DEFAULT_PORTS[parsedUrl.protocol] || null;
20600 }
20601
20602
20603 function parseAppUrl(relativeUrl, locationObj) {
20604   var prefixed = (relativeUrl.charAt(0) !== '/');
20605   if (prefixed) {
20606     relativeUrl = '/' + relativeUrl;
20607   }
20608   var match = urlResolve(relativeUrl);
20609   locationObj.$$path = decodeURIComponent(prefixed && match.pathname.charAt(0) === '/' ?
20610       match.pathname.substring(1) : match.pathname);
20611   locationObj.$$search = parseKeyValue(match.search);
20612   locationObj.$$hash = decodeURIComponent(match.hash);
20613
20614   // make sure path starts with '/';
20615   if (locationObj.$$path && locationObj.$$path.charAt(0) != '/') {
20616     locationObj.$$path = '/' + locationObj.$$path;
20617   }
20618 }
20619
20620
20621 /**
20622  *
20623  * @param {string} begin
20624  * @param {string} whole
20625  * @returns {string} returns text from whole after begin or undefined if it does not begin with
20626  *                   expected string.
20627  */
20628 function beginsWith(begin, whole) {
20629   if (whole.indexOf(begin) === 0) {
20630     return whole.substr(begin.length);
20631   }
20632 }
20633
20634
20635 function stripHash(url) {
20636   var index = url.indexOf('#');
20637   return index == -1 ? url : url.substr(0, index);
20638 }
20639
20640 function trimEmptyHash(url) {
20641   return url.replace(/(#.+)|#$/, '$1');
20642 }
20643
20644
20645 function stripFile(url) {
20646   return url.substr(0, stripHash(url).lastIndexOf('/') + 1);
20647 }
20648
20649 /* return the server only (scheme://host:port) */
20650 function serverBase(url) {
20651   return url.substring(0, url.indexOf('/', url.indexOf('//') + 2));
20652 }
20653
20654
20655 /**
20656  * LocationHtml5Url represents an url
20657  * This object is exposed as $location service when HTML5 mode is enabled and supported
20658  *
20659  * @constructor
20660  * @param {string} appBase application base URL
20661  * @param {string} appBaseNoFile application base URL stripped of any filename
20662  * @param {string} basePrefix url path prefix
20663  */
20664 function LocationHtml5Url(appBase, appBaseNoFile, basePrefix) {
20665   this.$$html5 = true;
20666   basePrefix = basePrefix || '';
20667   parseAbsoluteUrl(appBase, this);
20668
20669
20670   /**
20671    * Parse given html5 (regular) url string into properties
20672    * @param {string} url HTML5 url
20673    * @private
20674    */
20675   this.$$parse = function(url) {
20676     var pathUrl = beginsWith(appBaseNoFile, url);
20677     if (!isString(pathUrl)) {
20678       throw $locationMinErr('ipthprfx', 'Invalid url "{0}", missing path prefix "{1}".', url,
20679           appBaseNoFile);
20680     }
20681
20682     parseAppUrl(pathUrl, this);
20683
20684     if (!this.$$path) {
20685       this.$$path = '/';
20686     }
20687
20688     this.$$compose();
20689   };
20690
20691   /**
20692    * Compose url and update `absUrl` property
20693    * @private
20694    */
20695   this.$$compose = function() {
20696     var search = toKeyValue(this.$$search),
20697         hash = this.$$hash ? '#' + encodeUriSegment(this.$$hash) : '';
20698
20699     this.$$url = encodePath(this.$$path) + (search ? '?' + search : '') + hash;
20700     this.$$absUrl = appBaseNoFile + this.$$url.substr(1); // first char is always '/'
20701   };
20702
20703   this.$$parseLinkUrl = function(url, relHref) {
20704     if (relHref && relHref[0] === '#') {
20705       // special case for links to hash fragments:
20706       // keep the old url and only replace the hash fragment
20707       this.hash(relHref.slice(1));
20708       return true;
20709     }
20710     var appUrl, prevAppUrl;
20711     var rewrittenUrl;
20712
20713     if (isDefined(appUrl = beginsWith(appBase, url))) {
20714       prevAppUrl = appUrl;
20715       if (isDefined(appUrl = beginsWith(basePrefix, appUrl))) {
20716         rewrittenUrl = appBaseNoFile + (beginsWith('/', appUrl) || appUrl);
20717       } else {
20718         rewrittenUrl = appBase + prevAppUrl;
20719       }
20720     } else if (isDefined(appUrl = beginsWith(appBaseNoFile, url))) {
20721       rewrittenUrl = appBaseNoFile + appUrl;
20722     } else if (appBaseNoFile == url + '/') {
20723       rewrittenUrl = appBaseNoFile;
20724     }
20725     if (rewrittenUrl) {
20726       this.$$parse(rewrittenUrl);
20727     }
20728     return !!rewrittenUrl;
20729   };
20730 }
20731
20732
20733 /**
20734  * LocationHashbangUrl represents url
20735  * This object is exposed as $location service when developer doesn't opt into html5 mode.
20736  * It also serves as the base class for html5 mode fallback on legacy browsers.
20737  *
20738  * @constructor
20739  * @param {string} appBase application base URL
20740  * @param {string} appBaseNoFile application base URL stripped of any filename
20741  * @param {string} hashPrefix hashbang prefix
20742  */
20743 function LocationHashbangUrl(appBase, appBaseNoFile, hashPrefix) {
20744
20745   parseAbsoluteUrl(appBase, this);
20746
20747
20748   /**
20749    * Parse given hashbang url into properties
20750    * @param {string} url Hashbang url
20751    * @private
20752    */
20753   this.$$parse = function(url) {
20754     var withoutBaseUrl = beginsWith(appBase, url) || beginsWith(appBaseNoFile, url);
20755     var withoutHashUrl;
20756
20757     if (!isUndefined(withoutBaseUrl) && withoutBaseUrl.charAt(0) === '#') {
20758
20759       // The rest of the url starts with a hash so we have
20760       // got either a hashbang path or a plain hash fragment
20761       withoutHashUrl = beginsWith(hashPrefix, withoutBaseUrl);
20762       if (isUndefined(withoutHashUrl)) {
20763         // There was no hashbang prefix so we just have a hash fragment
20764         withoutHashUrl = withoutBaseUrl;
20765       }
20766
20767     } else {
20768       // There was no hashbang path nor hash fragment:
20769       // If we are in HTML5 mode we use what is left as the path;
20770       // Otherwise we ignore what is left
20771       if (this.$$html5) {
20772         withoutHashUrl = withoutBaseUrl;
20773       } else {
20774         withoutHashUrl = '';
20775         if (isUndefined(withoutBaseUrl)) {
20776           appBase = url;
20777           this.replace();
20778         }
20779       }
20780     }
20781
20782     parseAppUrl(withoutHashUrl, this);
20783
20784     this.$$path = removeWindowsDriveName(this.$$path, withoutHashUrl, appBase);
20785
20786     this.$$compose();
20787
20788     /*
20789      * In Windows, on an anchor node on documents loaded from
20790      * the filesystem, the browser will return a pathname
20791      * prefixed with the drive name ('/C:/path') when a
20792      * pathname without a drive is set:
20793      *  * a.setAttribute('href', '/foo')
20794      *   * a.pathname === '/C:/foo' //true
20795      *
20796      * Inside of Angular, we're always using pathnames that
20797      * do not include drive names for routing.
20798      */
20799     function removeWindowsDriveName(path, url, base) {
20800       /*
20801       Matches paths for file protocol on windows,
20802       such as /C:/foo/bar, and captures only /foo/bar.
20803       */
20804       var windowsFilePathExp = /^\/[A-Z]:(\/.*)/;
20805
20806       var firstPathSegmentMatch;
20807
20808       //Get the relative path from the input URL.
20809       if (url.indexOf(base) === 0) {
20810         url = url.replace(base, '');
20811       }
20812
20813       // The input URL intentionally contains a first path segment that ends with a colon.
20814       if (windowsFilePathExp.exec(url)) {
20815         return path;
20816       }
20817
20818       firstPathSegmentMatch = windowsFilePathExp.exec(path);
20819       return firstPathSegmentMatch ? firstPathSegmentMatch[1] : path;
20820     }
20821   };
20822
20823   /**
20824    * Compose hashbang url and update `absUrl` property
20825    * @private
20826    */
20827   this.$$compose = function() {
20828     var search = toKeyValue(this.$$search),
20829         hash = this.$$hash ? '#' + encodeUriSegment(this.$$hash) : '';
20830
20831     this.$$url = encodePath(this.$$path) + (search ? '?' + search : '') + hash;
20832     this.$$absUrl = appBase + (this.$$url ? hashPrefix + this.$$url : '');
20833   };
20834
20835   this.$$parseLinkUrl = function(url, relHref) {
20836     if (stripHash(appBase) == stripHash(url)) {
20837       this.$$parse(url);
20838       return true;
20839     }
20840     return false;
20841   };
20842 }
20843
20844
20845 /**
20846  * LocationHashbangUrl represents url
20847  * This object is exposed as $location service when html5 history api is enabled but the browser
20848  * does not support it.
20849  *
20850  * @constructor
20851  * @param {string} appBase application base URL
20852  * @param {string} appBaseNoFile application base URL stripped of any filename
20853  * @param {string} hashPrefix hashbang prefix
20854  */
20855 function LocationHashbangInHtml5Url(appBase, appBaseNoFile, hashPrefix) {
20856   this.$$html5 = true;
20857   LocationHashbangUrl.apply(this, arguments);
20858
20859   this.$$parseLinkUrl = function(url, relHref) {
20860     if (relHref && relHref[0] === '#') {
20861       // special case for links to hash fragments:
20862       // keep the old url and only replace the hash fragment
20863       this.hash(relHref.slice(1));
20864       return true;
20865     }
20866
20867     var rewrittenUrl;
20868     var appUrl;
20869
20870     if (appBase == stripHash(url)) {
20871       rewrittenUrl = url;
20872     } else if ((appUrl = beginsWith(appBaseNoFile, url))) {
20873       rewrittenUrl = appBase + hashPrefix + appUrl;
20874     } else if (appBaseNoFile === url + '/') {
20875       rewrittenUrl = appBaseNoFile;
20876     }
20877     if (rewrittenUrl) {
20878       this.$$parse(rewrittenUrl);
20879     }
20880     return !!rewrittenUrl;
20881   };
20882
20883   this.$$compose = function() {
20884     var search = toKeyValue(this.$$search),
20885         hash = this.$$hash ? '#' + encodeUriSegment(this.$$hash) : '';
20886
20887     this.$$url = encodePath(this.$$path) + (search ? '?' + search : '') + hash;
20888     // include hashPrefix in $$absUrl when $$url is empty so IE9 does not reload page because of removal of '#'
20889     this.$$absUrl = appBase + hashPrefix + this.$$url;
20890   };
20891
20892 }
20893
20894
20895 var locationPrototype = {
20896
20897   /**
20898    * Are we in html5 mode?
20899    * @private
20900    */
20901   $$html5: false,
20902
20903   /**
20904    * Has any change been replacing?
20905    * @private
20906    */
20907   $$replace: false,
20908
20909   /**
20910    * @ngdoc method
20911    * @name $location#absUrl
20912    *
20913    * @description
20914    * This method is getter only.
20915    *
20916    * Return full url representation with all segments encoded according to rules specified in
20917    * [RFC 3986](http://www.ietf.org/rfc/rfc3986.txt).
20918    *
20919    *
20920    * ```js
20921    * // given url http://example.com/#/some/path?foo=bar&baz=xoxo
20922    * var absUrl = $location.absUrl();
20923    * // => "http://example.com/#/some/path?foo=bar&baz=xoxo"
20924    * ```
20925    *
20926    * @return {string} full url
20927    */
20928   absUrl: locationGetter('$$absUrl'),
20929
20930   /**
20931    * @ngdoc method
20932    * @name $location#url
20933    *
20934    * @description
20935    * This method is getter / setter.
20936    *
20937    * Return url (e.g. `/path?a=b#hash`) when called without any parameter.
20938    *
20939    * Change path, search and hash, when called with parameter and return `$location`.
20940    *
20941    *
20942    * ```js
20943    * // given url http://example.com/#/some/path?foo=bar&baz=xoxo
20944    * var url = $location.url();
20945    * // => "/some/path?foo=bar&baz=xoxo"
20946    * ```
20947    *
20948    * @param {string=} url New url without base prefix (e.g. `/path?a=b#hash`)
20949    * @return {string} url
20950    */
20951   url: function(url) {
20952     if (isUndefined(url)) {
20953       return this.$$url;
20954     }
20955
20956     var match = PATH_MATCH.exec(url);
20957     if (match[1] || url === '') this.path(decodeURIComponent(match[1]));
20958     if (match[2] || match[1] || url === '') this.search(match[3] || '');
20959     this.hash(match[5] || '');
20960
20961     return this;
20962   },
20963
20964   /**
20965    * @ngdoc method
20966    * @name $location#protocol
20967    *
20968    * @description
20969    * This method is getter only.
20970    *
20971    * Return protocol of current url.
20972    *
20973    *
20974    * ```js
20975    * // given url http://example.com/#/some/path?foo=bar&baz=xoxo
20976    * var protocol = $location.protocol();
20977    * // => "http"
20978    * ```
20979    *
20980    * @return {string} protocol of current url
20981    */
20982   protocol: locationGetter('$$protocol'),
20983
20984   /**
20985    * @ngdoc method
20986    * @name $location#host
20987    *
20988    * @description
20989    * This method is getter only.
20990    *
20991    * Return host of current url.
20992    *
20993    * Note: compared to the non-angular version `location.host` which returns `hostname:port`, this returns the `hostname` portion only.
20994    *
20995    *
20996    * ```js
20997    * // given url http://example.com/#/some/path?foo=bar&baz=xoxo
20998    * var host = $location.host();
20999    * // => "example.com"
21000    *
21001    * // given url http://user:password@example.com:8080/#/some/path?foo=bar&baz=xoxo
21002    * host = $location.host();
21003    * // => "example.com"
21004    * host = location.host;
21005    * // => "example.com:8080"
21006    * ```
21007    *
21008    * @return {string} host of current url.
21009    */
21010   host: locationGetter('$$host'),
21011
21012   /**
21013    * @ngdoc method
21014    * @name $location#port
21015    *
21016    * @description
21017    * This method is getter only.
21018    *
21019    * Return port of current url.
21020    *
21021    *
21022    * ```js
21023    * // given url http://example.com/#/some/path?foo=bar&baz=xoxo
21024    * var port = $location.port();
21025    * // => 80
21026    * ```
21027    *
21028    * @return {Number} port
21029    */
21030   port: locationGetter('$$port'),
21031
21032   /**
21033    * @ngdoc method
21034    * @name $location#path
21035    *
21036    * @description
21037    * This method is getter / setter.
21038    *
21039    * Return path of current url when called without any parameter.
21040    *
21041    * Change path when called with parameter and return `$location`.
21042    *
21043    * Note: Path should always begin with forward slash (/), this method will add the forward slash
21044    * if it is missing.
21045    *
21046    *
21047    * ```js
21048    * // given url http://example.com/#/some/path?foo=bar&baz=xoxo
21049    * var path = $location.path();
21050    * // => "/some/path"
21051    * ```
21052    *
21053    * @param {(string|number)=} path New path
21054    * @return {string} path
21055    */
21056   path: locationGetterSetter('$$path', function(path) {
21057     path = path !== null ? path.toString() : '';
21058     return path.charAt(0) == '/' ? path : '/' + path;
21059   }),
21060
21061   /**
21062    * @ngdoc method
21063    * @name $location#search
21064    *
21065    * @description
21066    * This method is getter / setter.
21067    *
21068    * Return search part (as object) of current url when called without any parameter.
21069    *
21070    * Change search part when called with parameter and return `$location`.
21071    *
21072    *
21073    * ```js
21074    * // given url http://example.com/#/some/path?foo=bar&baz=xoxo
21075    * var searchObject = $location.search();
21076    * // => {foo: 'bar', baz: 'xoxo'}
21077    *
21078    * // set foo to 'yipee'
21079    * $location.search('foo', 'yipee');
21080    * // $location.search() => {foo: 'yipee', baz: 'xoxo'}
21081    * ```
21082    *
21083    * @param {string|Object.<string>|Object.<Array.<string>>} search New search params - string or
21084    * hash object.
21085    *
21086    * When called with a single argument the method acts as a setter, setting the `search` component
21087    * of `$location` to the specified value.
21088    *
21089    * If the argument is a hash object containing an array of values, these values will be encoded
21090    * as duplicate search parameters in the url.
21091    *
21092    * @param {(string|Number|Array<string>|boolean)=} paramValue If `search` is a string or number, then `paramValue`
21093    * will override only a single search property.
21094    *
21095    * If `paramValue` is an array, it will override the property of the `search` component of
21096    * `$location` specified via the first argument.
21097    *
21098    * If `paramValue` is `null`, the property specified via the first argument will be deleted.
21099    *
21100    * If `paramValue` is `true`, the property specified via the first argument will be added with no
21101    * value nor trailing equal sign.
21102    *
21103    * @return {Object} If called with no arguments returns the parsed `search` object. If called with
21104    * one or more arguments returns `$location` object itself.
21105    */
21106   search: function(search, paramValue) {
21107     switch (arguments.length) {
21108       case 0:
21109         return this.$$search;
21110       case 1:
21111         if (isString(search) || isNumber(search)) {
21112           search = search.toString();
21113           this.$$search = parseKeyValue(search);
21114         } else if (isObject(search)) {
21115           search = copy(search, {});
21116           // remove object undefined or null properties
21117           forEach(search, function(value, key) {
21118             if (value == null) delete search[key];
21119           });
21120
21121           this.$$search = search;
21122         } else {
21123           throw $locationMinErr('isrcharg',
21124               'The first argument of the `$location#search()` call must be a string or an object.');
21125         }
21126         break;
21127       default:
21128         if (isUndefined(paramValue) || paramValue === null) {
21129           delete this.$$search[search];
21130         } else {
21131           this.$$search[search] = paramValue;
21132         }
21133     }
21134
21135     this.$$compose();
21136     return this;
21137   },
21138
21139   /**
21140    * @ngdoc method
21141    * @name $location#hash
21142    *
21143    * @description
21144    * This method is getter / setter.
21145    *
21146    * Returns the hash fragment when called without any parameters.
21147    *
21148    * Changes the hash fragment when called with a parameter and returns `$location`.
21149    *
21150    *
21151    * ```js
21152    * // given url http://example.com/#/some/path?foo=bar&baz=xoxo#hashValue
21153    * var hash = $location.hash();
21154    * // => "hashValue"
21155    * ```
21156    *
21157    * @param {(string|number)=} hash New hash fragment
21158    * @return {string} hash
21159    */
21160   hash: locationGetterSetter('$$hash', function(hash) {
21161     return hash !== null ? hash.toString() : '';
21162   }),
21163
21164   /**
21165    * @ngdoc method
21166    * @name $location#replace
21167    *
21168    * @description
21169    * If called, all changes to $location during the current `$digest` will replace the current history
21170    * record, instead of adding a new one.
21171    */
21172   replace: function() {
21173     this.$$replace = true;
21174     return this;
21175   }
21176 };
21177
21178 forEach([LocationHashbangInHtml5Url, LocationHashbangUrl, LocationHtml5Url], function(Location) {
21179   Location.prototype = Object.create(locationPrototype);
21180
21181   /**
21182    * @ngdoc method
21183    * @name $location#state
21184    *
21185    * @description
21186    * This method is getter / setter.
21187    *
21188    * Return the history state object when called without any parameter.
21189    *
21190    * Change the history state object when called with one parameter and return `$location`.
21191    * The state object is later passed to `pushState` or `replaceState`.
21192    *
21193    * NOTE: This method is supported only in HTML5 mode and only in browsers supporting
21194    * the HTML5 History API (i.e. methods `pushState` and `replaceState`). If you need to support
21195    * older browsers (like IE9 or Android < 4.0), don't use this method.
21196    *
21197    * @param {object=} state State object for pushState or replaceState
21198    * @return {object} state
21199    */
21200   Location.prototype.state = function(state) {
21201     if (!arguments.length) {
21202       return this.$$state;
21203     }
21204
21205     if (Location !== LocationHtml5Url || !this.$$html5) {
21206       throw $locationMinErr('nostate', 'History API state support is available only ' +
21207         'in HTML5 mode and only in browsers supporting HTML5 History API');
21208     }
21209     // The user might modify `stateObject` after invoking `$location.state(stateObject)`
21210     // but we're changing the $$state reference to $browser.state() during the $digest
21211     // so the modification window is narrow.
21212     this.$$state = isUndefined(state) ? null : state;
21213
21214     return this;
21215   };
21216 });
21217
21218
21219 function locationGetter(property) {
21220   return function() {
21221     return this[property];
21222   };
21223 }
21224
21225
21226 function locationGetterSetter(property, preprocess) {
21227   return function(value) {
21228     if (isUndefined(value)) {
21229       return this[property];
21230     }
21231
21232     this[property] = preprocess(value);
21233     this.$$compose();
21234
21235     return this;
21236   };
21237 }
21238
21239
21240 /**
21241  * @ngdoc service
21242  * @name $location
21243  *
21244  * @requires $rootElement
21245  *
21246  * @description
21247  * The $location service parses the URL in the browser address bar (based on the
21248  * [window.location](https://developer.mozilla.org/en/window.location)) and makes the URL
21249  * available to your application. Changes to the URL in the address bar are reflected into
21250  * $location service and changes to $location are reflected into the browser address bar.
21251  *
21252  * **The $location service:**
21253  *
21254  * - Exposes the current URL in the browser address bar, so you can
21255  *   - Watch and observe the URL.
21256  *   - Change the URL.
21257  * - Synchronizes the URL with the browser when the user
21258  *   - Changes the address bar.
21259  *   - Clicks the back or forward button (or clicks a History link).
21260  *   - Clicks on a link.
21261  * - Represents the URL object as a set of methods (protocol, host, port, path, search, hash).
21262  *
21263  * For more information see {@link guide/$location Developer Guide: Using $location}
21264  */
21265
21266 /**
21267  * @ngdoc provider
21268  * @name $locationProvider
21269  * @description
21270  * Use the `$locationProvider` to configure how the application deep linking paths are stored.
21271  */
21272 function $LocationProvider() {
21273   var hashPrefix = '',
21274       html5Mode = {
21275         enabled: false,
21276         requireBase: true,
21277         rewriteLinks: true
21278       };
21279
21280   /**
21281    * @ngdoc method
21282    * @name $locationProvider#hashPrefix
21283    * @description
21284    * @param {string=} prefix Prefix for hash part (containing path and search)
21285    * @returns {*} current value if used as getter or itself (chaining) if used as setter
21286    */
21287   this.hashPrefix = function(prefix) {
21288     if (isDefined(prefix)) {
21289       hashPrefix = prefix;
21290       return this;
21291     } else {
21292       return hashPrefix;
21293     }
21294   };
21295
21296   /**
21297    * @ngdoc method
21298    * @name $locationProvider#html5Mode
21299    * @description
21300    * @param {(boolean|Object)=} mode If boolean, sets `html5Mode.enabled` to value.
21301    *   If object, sets `enabled`, `requireBase` and `rewriteLinks` to respective values. Supported
21302    *   properties:
21303    *   - **enabled** – `{boolean}` – (default: false) If true, will rely on `history.pushState` to
21304    *     change urls where supported. Will fall back to hash-prefixed paths in browsers that do not
21305    *     support `pushState`.
21306    *   - **requireBase** - `{boolean}` - (default: `true`) When html5Mode is enabled, specifies
21307    *     whether or not a <base> tag is required to be present. If `enabled` and `requireBase` are
21308    *     true, and a base tag is not present, an error will be thrown when `$location` is injected.
21309    *     See the {@link guide/$location $location guide for more information}
21310    *   - **rewriteLinks** - `{boolean}` - (default: `true`) When html5Mode is enabled,
21311    *     enables/disables url rewriting for relative links.
21312    *
21313    * @returns {Object} html5Mode object if used as getter or itself (chaining) if used as setter
21314    */
21315   this.html5Mode = function(mode) {
21316     if (isBoolean(mode)) {
21317       html5Mode.enabled = mode;
21318       return this;
21319     } else if (isObject(mode)) {
21320
21321       if (isBoolean(mode.enabled)) {
21322         html5Mode.enabled = mode.enabled;
21323       }
21324
21325       if (isBoolean(mode.requireBase)) {
21326         html5Mode.requireBase = mode.requireBase;
21327       }
21328
21329       if (isBoolean(mode.rewriteLinks)) {
21330         html5Mode.rewriteLinks = mode.rewriteLinks;
21331       }
21332
21333       return this;
21334     } else {
21335       return html5Mode;
21336     }
21337   };
21338
21339   /**
21340    * @ngdoc event
21341    * @name $location#$locationChangeStart
21342    * @eventType broadcast on root scope
21343    * @description
21344    * Broadcasted before a URL will change.
21345    *
21346    * This change can be prevented by calling
21347    * `preventDefault` method of the event. See {@link ng.$rootScope.Scope#$on} for more
21348    * details about event object. Upon successful change
21349    * {@link ng.$location#$locationChangeSuccess $locationChangeSuccess} is fired.
21350    *
21351    * The `newState` and `oldState` parameters may be defined only in HTML5 mode and when
21352    * the browser supports the HTML5 History API.
21353    *
21354    * @param {Object} angularEvent Synthetic event object.
21355    * @param {string} newUrl New URL
21356    * @param {string=} oldUrl URL that was before it was changed.
21357    * @param {string=} newState New history state object
21358    * @param {string=} oldState History state object that was before it was changed.
21359    */
21360
21361   /**
21362    * @ngdoc event
21363    * @name $location#$locationChangeSuccess
21364    * @eventType broadcast on root scope
21365    * @description
21366    * Broadcasted after a URL was changed.
21367    *
21368    * The `newState` and `oldState` parameters may be defined only in HTML5 mode and when
21369    * the browser supports the HTML5 History API.
21370    *
21371    * @param {Object} angularEvent Synthetic event object.
21372    * @param {string} newUrl New URL
21373    * @param {string=} oldUrl URL that was before it was changed.
21374    * @param {string=} newState New history state object
21375    * @param {string=} oldState History state object that was before it was changed.
21376    */
21377
21378   this.$get = ['$rootScope', '$browser', '$sniffer', '$rootElement', '$window',
21379       function($rootScope, $browser, $sniffer, $rootElement, $window) {
21380     var $location,
21381         LocationMode,
21382         baseHref = $browser.baseHref(), // if base[href] is undefined, it defaults to ''
21383         initialUrl = $browser.url(),
21384         appBase;
21385
21386     if (html5Mode.enabled) {
21387       if (!baseHref && html5Mode.requireBase) {
21388         throw $locationMinErr('nobase',
21389           "$location in HTML5 mode requires a <base> tag to be present!");
21390       }
21391       appBase = serverBase(initialUrl) + (baseHref || '/');
21392       LocationMode = $sniffer.history ? LocationHtml5Url : LocationHashbangInHtml5Url;
21393     } else {
21394       appBase = stripHash(initialUrl);
21395       LocationMode = LocationHashbangUrl;
21396     }
21397     var appBaseNoFile = stripFile(appBase);
21398
21399     $location = new LocationMode(appBase, appBaseNoFile, '#' + hashPrefix);
21400     $location.$$parseLinkUrl(initialUrl, initialUrl);
21401
21402     $location.$$state = $browser.state();
21403
21404     var IGNORE_URI_REGEXP = /^\s*(javascript|mailto):/i;
21405
21406     function setBrowserUrlWithFallback(url, replace, state) {
21407       var oldUrl = $location.url();
21408       var oldState = $location.$$state;
21409       try {
21410         $browser.url(url, replace, state);
21411
21412         // Make sure $location.state() returns referentially identical (not just deeply equal)
21413         // state object; this makes possible quick checking if the state changed in the digest
21414         // loop. Checking deep equality would be too expensive.
21415         $location.$$state = $browser.state();
21416       } catch (e) {
21417         // Restore old values if pushState fails
21418         $location.url(oldUrl);
21419         $location.$$state = oldState;
21420
21421         throw e;
21422       }
21423     }
21424
21425     $rootElement.on('click', function(event) {
21426       // TODO(vojta): rewrite link when opening in new tab/window (in legacy browser)
21427       // currently we open nice url link and redirect then
21428
21429       if (!html5Mode.rewriteLinks || event.ctrlKey || event.metaKey || event.shiftKey || event.which == 2 || event.button == 2) return;
21430
21431       var elm = jqLite(event.target);
21432
21433       // traverse the DOM up to find first A tag
21434       while (nodeName_(elm[0]) !== 'a') {
21435         // ignore rewriting if no A tag (reached root element, or no parent - removed from document)
21436         if (elm[0] === $rootElement[0] || !(elm = elm.parent())[0]) return;
21437       }
21438
21439       var absHref = elm.prop('href');
21440       // get the actual href attribute - see
21441       // http://msdn.microsoft.com/en-us/library/ie/dd347148(v=vs.85).aspx
21442       var relHref = elm.attr('href') || elm.attr('xlink:href');
21443
21444       if (isObject(absHref) && absHref.toString() === '[object SVGAnimatedString]') {
21445         // SVGAnimatedString.animVal should be identical to SVGAnimatedString.baseVal, unless during
21446         // an animation.
21447         absHref = urlResolve(absHref.animVal).href;
21448       }
21449
21450       // Ignore when url is started with javascript: or mailto:
21451       if (IGNORE_URI_REGEXP.test(absHref)) return;
21452
21453       if (absHref && !elm.attr('target') && !event.isDefaultPrevented()) {
21454         if ($location.$$parseLinkUrl(absHref, relHref)) {
21455           // We do a preventDefault for all urls that are part of the angular application,
21456           // in html5mode and also without, so that we are able to abort navigation without
21457           // getting double entries in the location history.
21458           event.preventDefault();
21459           // update location manually
21460           if ($location.absUrl() != $browser.url()) {
21461             $rootScope.$apply();
21462             // hack to work around FF6 bug 684208 when scenario runner clicks on links
21463             $window.angular['ff-684208-preventDefault'] = true;
21464           }
21465         }
21466       }
21467     });
21468
21469
21470     // rewrite hashbang url <> html5 url
21471     if (trimEmptyHash($location.absUrl()) != trimEmptyHash(initialUrl)) {
21472       $browser.url($location.absUrl(), true);
21473     }
21474
21475     var initializing = true;
21476
21477     // update $location when $browser url changes
21478     $browser.onUrlChange(function(newUrl, newState) {
21479
21480       if (isUndefined(beginsWith(appBaseNoFile, newUrl))) {
21481         // If we are navigating outside of the app then force a reload
21482         $window.location.href = newUrl;
21483         return;
21484       }
21485
21486       $rootScope.$evalAsync(function() {
21487         var oldUrl = $location.absUrl();
21488         var oldState = $location.$$state;
21489         var defaultPrevented;
21490         newUrl = trimEmptyHash(newUrl);
21491         $location.$$parse(newUrl);
21492         $location.$$state = newState;
21493
21494         defaultPrevented = $rootScope.$broadcast('$locationChangeStart', newUrl, oldUrl,
21495             newState, oldState).defaultPrevented;
21496
21497         // if the location was changed by a `$locationChangeStart` handler then stop
21498         // processing this location change
21499         if ($location.absUrl() !== newUrl) return;
21500
21501         if (defaultPrevented) {
21502           $location.$$parse(oldUrl);
21503           $location.$$state = oldState;
21504           setBrowserUrlWithFallback(oldUrl, false, oldState);
21505         } else {
21506           initializing = false;
21507           afterLocationChange(oldUrl, oldState);
21508         }
21509       });
21510       if (!$rootScope.$$phase) $rootScope.$digest();
21511     });
21512
21513     // update browser
21514     $rootScope.$watch(function $locationWatch() {
21515       var oldUrl = trimEmptyHash($browser.url());
21516       var newUrl = trimEmptyHash($location.absUrl());
21517       var oldState = $browser.state();
21518       var currentReplace = $location.$$replace;
21519       var urlOrStateChanged = oldUrl !== newUrl ||
21520         ($location.$$html5 && $sniffer.history && oldState !== $location.$$state);
21521
21522       if (initializing || urlOrStateChanged) {
21523         initializing = false;
21524
21525         $rootScope.$evalAsync(function() {
21526           var newUrl = $location.absUrl();
21527           var defaultPrevented = $rootScope.$broadcast('$locationChangeStart', newUrl, oldUrl,
21528               $location.$$state, oldState).defaultPrevented;
21529
21530           // if the location was changed by a `$locationChangeStart` handler then stop
21531           // processing this location change
21532           if ($location.absUrl() !== newUrl) return;
21533
21534           if (defaultPrevented) {
21535             $location.$$parse(oldUrl);
21536             $location.$$state = oldState;
21537           } else {
21538             if (urlOrStateChanged) {
21539               setBrowserUrlWithFallback(newUrl, currentReplace,
21540                                         oldState === $location.$$state ? null : $location.$$state);
21541             }
21542             afterLocationChange(oldUrl, oldState);
21543           }
21544         });
21545       }
21546
21547       $location.$$replace = false;
21548
21549       // we don't need to return anything because $evalAsync will make the digest loop dirty when
21550       // there is a change
21551     });
21552
21553     return $location;
21554
21555     function afterLocationChange(oldUrl, oldState) {
21556       $rootScope.$broadcast('$locationChangeSuccess', $location.absUrl(), oldUrl,
21557         $location.$$state, oldState);
21558     }
21559 }];
21560 }
21561
21562 /**
21563  * @ngdoc service
21564  * @name $log
21565  * @requires $window
21566  *
21567  * @description
21568  * Simple service for logging. Default implementation safely writes the message
21569  * into the browser's console (if present).
21570  *
21571  * The main purpose of this service is to simplify debugging and troubleshooting.
21572  *
21573  * The default is to log `debug` messages. You can use
21574  * {@link ng.$logProvider ng.$logProvider#debugEnabled} to change this.
21575  *
21576  * @example
21577    <example module="logExample">
21578      <file name="script.js">
21579        angular.module('logExample', [])
21580          .controller('LogController', ['$scope', '$log', function($scope, $log) {
21581            $scope.$log = $log;
21582            $scope.message = 'Hello World!';
21583          }]);
21584      </file>
21585      <file name="index.html">
21586        <div ng-controller="LogController">
21587          <p>Reload this page with open console, enter text and hit the log button...</p>
21588          <label>Message:
21589          <input type="text" ng-model="message" /></label>
21590          <button ng-click="$log.log(message)">log</button>
21591          <button ng-click="$log.warn(message)">warn</button>
21592          <button ng-click="$log.info(message)">info</button>
21593          <button ng-click="$log.error(message)">error</button>
21594          <button ng-click="$log.debug(message)">debug</button>
21595        </div>
21596      </file>
21597    </example>
21598  */
21599
21600 /**
21601  * @ngdoc provider
21602  * @name $logProvider
21603  * @description
21604  * Use the `$logProvider` to configure how the application logs messages
21605  */
21606 function $LogProvider() {
21607   var debug = true,
21608       self = this;
21609
21610   /**
21611    * @ngdoc method
21612    * @name $logProvider#debugEnabled
21613    * @description
21614    * @param {boolean=} flag enable or disable debug level messages
21615    * @returns {*} current value if used as getter or itself (chaining) if used as setter
21616    */
21617   this.debugEnabled = function(flag) {
21618     if (isDefined(flag)) {
21619       debug = flag;
21620     return this;
21621     } else {
21622       return debug;
21623     }
21624   };
21625
21626   this.$get = ['$window', function($window) {
21627     return {
21628       /**
21629        * @ngdoc method
21630        * @name $log#log
21631        *
21632        * @description
21633        * Write a log message
21634        */
21635       log: consoleLog('log'),
21636
21637       /**
21638        * @ngdoc method
21639        * @name $log#info
21640        *
21641        * @description
21642        * Write an information message
21643        */
21644       info: consoleLog('info'),
21645
21646       /**
21647        * @ngdoc method
21648        * @name $log#warn
21649        *
21650        * @description
21651        * Write a warning message
21652        */
21653       warn: consoleLog('warn'),
21654
21655       /**
21656        * @ngdoc method
21657        * @name $log#error
21658        *
21659        * @description
21660        * Write an error message
21661        */
21662       error: consoleLog('error'),
21663
21664       /**
21665        * @ngdoc method
21666        * @name $log#debug
21667        *
21668        * @description
21669        * Write a debug message
21670        */
21671       debug: (function() {
21672         var fn = consoleLog('debug');
21673
21674         return function() {
21675           if (debug) {
21676             fn.apply(self, arguments);
21677           }
21678         };
21679       }())
21680     };
21681
21682     function formatError(arg) {
21683       if (arg instanceof Error) {
21684         if (arg.stack) {
21685           arg = (arg.message && arg.stack.indexOf(arg.message) === -1)
21686               ? 'Error: ' + arg.message + '\n' + arg.stack
21687               : arg.stack;
21688         } else if (arg.sourceURL) {
21689           arg = arg.message + '\n' + arg.sourceURL + ':' + arg.line;
21690         }
21691       }
21692       return arg;
21693     }
21694
21695     function consoleLog(type) {
21696       var console = $window.console || {},
21697           logFn = console[type] || console.log || noop,
21698           hasApply = false;
21699
21700       // Note: reading logFn.apply throws an error in IE11 in IE8 document mode.
21701       // The reason behind this is that console.log has type "object" in IE8...
21702       try {
21703         hasApply = !!logFn.apply;
21704       } catch (e) {}
21705
21706       if (hasApply) {
21707         return function() {
21708           var args = [];
21709           forEach(arguments, function(arg) {
21710             args.push(formatError(arg));
21711           });
21712           return logFn.apply(console, args);
21713         };
21714       }
21715
21716       // we are IE which either doesn't have window.console => this is noop and we do nothing,
21717       // or we are IE where console.log doesn't have apply so we log at least first 2 args
21718       return function(arg1, arg2) {
21719         logFn(arg1, arg2 == null ? '' : arg2);
21720       };
21721     }
21722   }];
21723 }
21724
21725 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
21726  *     Any commits to this file should be reviewed with security in mind.  *
21727  *   Changes to this file can potentially create security vulnerabilities. *
21728  *          An approval from 2 Core members with history of modifying      *
21729  *                         this file is required.                          *
21730  *                                                                         *
21731  *  Does the change somehow allow for arbitrary javascript to be executed? *
21732  *    Or allows for someone to change the prototype of built-in objects?   *
21733  *     Or gives undesired access to variables likes document or window?    *
21734  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
21735
21736 var $parseMinErr = minErr('$parse');
21737
21738 // Sandboxing Angular Expressions
21739 // ------------------------------
21740 // Angular expressions are generally considered safe because these expressions only have direct
21741 // access to `$scope` and locals. However, one can obtain the ability to execute arbitrary JS code by
21742 // obtaining a reference to native JS functions such as the Function constructor.
21743 //
21744 // As an example, consider the following Angular expression:
21745 //
21746 //   {}.toString.constructor('alert("evil JS code")')
21747 //
21748 // This sandboxing technique is not perfect and doesn't aim to be. The goal is to prevent exploits
21749 // against the expression language, but not to prevent exploits that were enabled by exposing
21750 // sensitive JavaScript or browser APIs on Scope. Exposing such objects on a Scope is never a good
21751 // practice and therefore we are not even trying to protect against interaction with an object
21752 // explicitly exposed in this way.
21753 //
21754 // In general, it is not possible to access a Window object from an angular expression unless a
21755 // window or some DOM object that has a reference to window is published onto a Scope.
21756 // Similarly we prevent invocations of function known to be dangerous, as well as assignments to
21757 // native objects.
21758 //
21759 // See https://docs.angularjs.org/guide/security
21760
21761
21762 function ensureSafeMemberName(name, fullExpression) {
21763   if (name === "__defineGetter__" || name === "__defineSetter__"
21764       || name === "__lookupGetter__" || name === "__lookupSetter__"
21765       || name === "__proto__") {
21766     throw $parseMinErr('isecfld',
21767         'Attempting to access a disallowed field in Angular expressions! '
21768         + 'Expression: {0}', fullExpression);
21769   }
21770   return name;
21771 }
21772
21773 function getStringValue(name, fullExpression) {
21774   // From the JavaScript docs:
21775   // Property names must be strings. This means that non-string objects cannot be used
21776   // as keys in an object. Any non-string object, including a number, is typecasted
21777   // into a string via the toString method.
21778   //
21779   // So, to ensure that we are checking the same `name` that JavaScript would use,
21780   // we cast it to a string, if possible.
21781   // Doing `name + ''` can cause a repl error if the result to `toString` is not a string,
21782   // this is, this will handle objects that misbehave.
21783   name = name + '';
21784   if (!isString(name)) {
21785     throw $parseMinErr('iseccst',
21786         'Cannot convert object to primitive value! '
21787         + 'Expression: {0}', fullExpression);
21788   }
21789   return name;
21790 }
21791
21792 function ensureSafeObject(obj, fullExpression) {
21793   // nifty check if obj is Function that is fast and works across iframes and other contexts
21794   if (obj) {
21795     if (obj.constructor === obj) {
21796       throw $parseMinErr('isecfn',
21797           'Referencing Function in Angular expressions is disallowed! Expression: {0}',
21798           fullExpression);
21799     } else if (// isWindow(obj)
21800         obj.window === obj) {
21801       throw $parseMinErr('isecwindow',
21802           'Referencing the Window in Angular expressions is disallowed! Expression: {0}',
21803           fullExpression);
21804     } else if (// isElement(obj)
21805         obj.children && (obj.nodeName || (obj.prop && obj.attr && obj.find))) {
21806       throw $parseMinErr('isecdom',
21807           'Referencing DOM nodes in Angular expressions is disallowed! Expression: {0}',
21808           fullExpression);
21809     } else if (// block Object so that we can't get hold of dangerous Object.* methods
21810         obj === Object) {
21811       throw $parseMinErr('isecobj',
21812           'Referencing Object in Angular expressions is disallowed! Expression: {0}',
21813           fullExpression);
21814     }
21815   }
21816   return obj;
21817 }
21818
21819 var CALL = Function.prototype.call;
21820 var APPLY = Function.prototype.apply;
21821 var BIND = Function.prototype.bind;
21822
21823 function ensureSafeFunction(obj, fullExpression) {
21824   if (obj) {
21825     if (obj.constructor === obj) {
21826       throw $parseMinErr('isecfn',
21827         'Referencing Function in Angular expressions is disallowed! Expression: {0}',
21828         fullExpression);
21829     } else if (obj === CALL || obj === APPLY || obj === BIND) {
21830       throw $parseMinErr('isecff',
21831         'Referencing call, apply or bind in Angular expressions is disallowed! Expression: {0}',
21832         fullExpression);
21833     }
21834   }
21835 }
21836
21837 function ensureSafeAssignContext(obj, fullExpression) {
21838   if (obj) {
21839     if (obj === (0).constructor || obj === (false).constructor || obj === ''.constructor ||
21840         obj === {}.constructor || obj === [].constructor || obj === Function.constructor) {
21841       throw $parseMinErr('isecaf',
21842         'Assigning to a constructor is disallowed! Expression: {0}', fullExpression);
21843     }
21844   }
21845 }
21846
21847 var OPERATORS = createMap();
21848 forEach('+ - * / % === !== == != < > <= >= && || ! = |'.split(' '), function(operator) { OPERATORS[operator] = true; });
21849 var ESCAPE = {"n":"\n", "f":"\f", "r":"\r", "t":"\t", "v":"\v", "'":"'", '"':'"'};
21850
21851
21852 /////////////////////////////////////////
21853
21854
21855 /**
21856  * @constructor
21857  */
21858 var Lexer = function(options) {
21859   this.options = options;
21860 };
21861
21862 Lexer.prototype = {
21863   constructor: Lexer,
21864
21865   lex: function(text) {
21866     this.text = text;
21867     this.index = 0;
21868     this.tokens = [];
21869
21870     while (this.index < this.text.length) {
21871       var ch = this.text.charAt(this.index);
21872       if (ch === '"' || ch === "'") {
21873         this.readString(ch);
21874       } else if (this.isNumber(ch) || ch === '.' && this.isNumber(this.peek())) {
21875         this.readNumber();
21876       } else if (this.isIdent(ch)) {
21877         this.readIdent();
21878       } else if (this.is(ch, '(){}[].,;:?')) {
21879         this.tokens.push({index: this.index, text: ch});
21880         this.index++;
21881       } else if (this.isWhitespace(ch)) {
21882         this.index++;
21883       } else {
21884         var ch2 = ch + this.peek();
21885         var ch3 = ch2 + this.peek(2);
21886         var op1 = OPERATORS[ch];
21887         var op2 = OPERATORS[ch2];
21888         var op3 = OPERATORS[ch3];
21889         if (op1 || op2 || op3) {
21890           var token = op3 ? ch3 : (op2 ? ch2 : ch);
21891           this.tokens.push({index: this.index, text: token, operator: true});
21892           this.index += token.length;
21893         } else {
21894           this.throwError('Unexpected next character ', this.index, this.index + 1);
21895         }
21896       }
21897     }
21898     return this.tokens;
21899   },
21900
21901   is: function(ch, chars) {
21902     return chars.indexOf(ch) !== -1;
21903   },
21904
21905   peek: function(i) {
21906     var num = i || 1;
21907     return (this.index + num < this.text.length) ? this.text.charAt(this.index + num) : false;
21908   },
21909
21910   isNumber: function(ch) {
21911     return ('0' <= ch && ch <= '9') && typeof ch === "string";
21912   },
21913
21914   isWhitespace: function(ch) {
21915     // IE treats non-breaking space as \u00A0
21916     return (ch === ' ' || ch === '\r' || ch === '\t' ||
21917             ch === '\n' || ch === '\v' || ch === '\u00A0');
21918   },
21919
21920   isIdent: function(ch) {
21921     return ('a' <= ch && ch <= 'z' ||
21922             'A' <= ch && ch <= 'Z' ||
21923             '_' === ch || ch === '$');
21924   },
21925
21926   isExpOperator: function(ch) {
21927     return (ch === '-' || ch === '+' || this.isNumber(ch));
21928   },
21929
21930   throwError: function(error, start, end) {
21931     end = end || this.index;
21932     var colStr = (isDefined(start)
21933             ? 's ' + start +  '-' + this.index + ' [' + this.text.substring(start, end) + ']'
21934             : ' ' + end);
21935     throw $parseMinErr('lexerr', 'Lexer Error: {0} at column{1} in expression [{2}].',
21936         error, colStr, this.text);
21937   },
21938
21939   readNumber: function() {
21940     var number = '';
21941     var start = this.index;
21942     while (this.index < this.text.length) {
21943       var ch = lowercase(this.text.charAt(this.index));
21944       if (ch == '.' || this.isNumber(ch)) {
21945         number += ch;
21946       } else {
21947         var peekCh = this.peek();
21948         if (ch == 'e' && this.isExpOperator(peekCh)) {
21949           number += ch;
21950         } else if (this.isExpOperator(ch) &&
21951             peekCh && this.isNumber(peekCh) &&
21952             number.charAt(number.length - 1) == 'e') {
21953           number += ch;
21954         } else if (this.isExpOperator(ch) &&
21955             (!peekCh || !this.isNumber(peekCh)) &&
21956             number.charAt(number.length - 1) == 'e') {
21957           this.throwError('Invalid exponent');
21958         } else {
21959           break;
21960         }
21961       }
21962       this.index++;
21963     }
21964     this.tokens.push({
21965       index: start,
21966       text: number,
21967       constant: true,
21968       value: Number(number)
21969     });
21970   },
21971
21972   readIdent: function() {
21973     var start = this.index;
21974     while (this.index < this.text.length) {
21975       var ch = this.text.charAt(this.index);
21976       if (!(this.isIdent(ch) || this.isNumber(ch))) {
21977         break;
21978       }
21979       this.index++;
21980     }
21981     this.tokens.push({
21982       index: start,
21983       text: this.text.slice(start, this.index),
21984       identifier: true
21985     });
21986   },
21987
21988   readString: function(quote) {
21989     var start = this.index;
21990     this.index++;
21991     var string = '';
21992     var rawString = quote;
21993     var escape = false;
21994     while (this.index < this.text.length) {
21995       var ch = this.text.charAt(this.index);
21996       rawString += ch;
21997       if (escape) {
21998         if (ch === 'u') {
21999           var hex = this.text.substring(this.index + 1, this.index + 5);
22000           if (!hex.match(/[\da-f]{4}/i)) {
22001             this.throwError('Invalid unicode escape [\\u' + hex + ']');
22002           }
22003           this.index += 4;
22004           string += String.fromCharCode(parseInt(hex, 16));
22005         } else {
22006           var rep = ESCAPE[ch];
22007           string = string + (rep || ch);
22008         }
22009         escape = false;
22010       } else if (ch === '\\') {
22011         escape = true;
22012       } else if (ch === quote) {
22013         this.index++;
22014         this.tokens.push({
22015           index: start,
22016           text: rawString,
22017           constant: true,
22018           value: string
22019         });
22020         return;
22021       } else {
22022         string += ch;
22023       }
22024       this.index++;
22025     }
22026     this.throwError('Unterminated quote', start);
22027   }
22028 };
22029
22030 var AST = function(lexer, options) {
22031   this.lexer = lexer;
22032   this.options = options;
22033 };
22034
22035 AST.Program = 'Program';
22036 AST.ExpressionStatement = 'ExpressionStatement';
22037 AST.AssignmentExpression = 'AssignmentExpression';
22038 AST.ConditionalExpression = 'ConditionalExpression';
22039 AST.LogicalExpression = 'LogicalExpression';
22040 AST.BinaryExpression = 'BinaryExpression';
22041 AST.UnaryExpression = 'UnaryExpression';
22042 AST.CallExpression = 'CallExpression';
22043 AST.MemberExpression = 'MemberExpression';
22044 AST.Identifier = 'Identifier';
22045 AST.Literal = 'Literal';
22046 AST.ArrayExpression = 'ArrayExpression';
22047 AST.Property = 'Property';
22048 AST.ObjectExpression = 'ObjectExpression';
22049 AST.ThisExpression = 'ThisExpression';
22050
22051 // Internal use only
22052 AST.NGValueParameter = 'NGValueParameter';
22053
22054 AST.prototype = {
22055   ast: function(text) {
22056     this.text = text;
22057     this.tokens = this.lexer.lex(text);
22058
22059     var value = this.program();
22060
22061     if (this.tokens.length !== 0) {
22062       this.throwError('is an unexpected token', this.tokens[0]);
22063     }
22064
22065     return value;
22066   },
22067
22068   program: function() {
22069     var body = [];
22070     while (true) {
22071       if (this.tokens.length > 0 && !this.peek('}', ')', ';', ']'))
22072         body.push(this.expressionStatement());
22073       if (!this.expect(';')) {
22074         return { type: AST.Program, body: body};
22075       }
22076     }
22077   },
22078
22079   expressionStatement: function() {
22080     return { type: AST.ExpressionStatement, expression: this.filterChain() };
22081   },
22082
22083   filterChain: function() {
22084     var left = this.expression();
22085     var token;
22086     while ((token = this.expect('|'))) {
22087       left = this.filter(left);
22088     }
22089     return left;
22090   },
22091
22092   expression: function() {
22093     return this.assignment();
22094   },
22095
22096   assignment: function() {
22097     var result = this.ternary();
22098     if (this.expect('=')) {
22099       result = { type: AST.AssignmentExpression, left: result, right: this.assignment(), operator: '='};
22100     }
22101     return result;
22102   },
22103
22104   ternary: function() {
22105     var test = this.logicalOR();
22106     var alternate;
22107     var consequent;
22108     if (this.expect('?')) {
22109       alternate = this.expression();
22110       if (this.consume(':')) {
22111         consequent = this.expression();
22112         return { type: AST.ConditionalExpression, test: test, alternate: alternate, consequent: consequent};
22113       }
22114     }
22115     return test;
22116   },
22117
22118   logicalOR: function() {
22119     var left = this.logicalAND();
22120     while (this.expect('||')) {
22121       left = { type: AST.LogicalExpression, operator: '||', left: left, right: this.logicalAND() };
22122     }
22123     return left;
22124   },
22125
22126   logicalAND: function() {
22127     var left = this.equality();
22128     while (this.expect('&&')) {
22129       left = { type: AST.LogicalExpression, operator: '&&', left: left, right: this.equality()};
22130     }
22131     return left;
22132   },
22133
22134   equality: function() {
22135     var left = this.relational();
22136     var token;
22137     while ((token = this.expect('==','!=','===','!=='))) {
22138       left = { type: AST.BinaryExpression, operator: token.text, left: left, right: this.relational() };
22139     }
22140     return left;
22141   },
22142
22143   relational: function() {
22144     var left = this.additive();
22145     var token;
22146     while ((token = this.expect('<', '>', '<=', '>='))) {
22147       left = { type: AST.BinaryExpression, operator: token.text, left: left, right: this.additive() };
22148     }
22149     return left;
22150   },
22151
22152   additive: function() {
22153     var left = this.multiplicative();
22154     var token;
22155     while ((token = this.expect('+','-'))) {
22156       left = { type: AST.BinaryExpression, operator: token.text, left: left, right: this.multiplicative() };
22157     }
22158     return left;
22159   },
22160
22161   multiplicative: function() {
22162     var left = this.unary();
22163     var token;
22164     while ((token = this.expect('*','/','%'))) {
22165       left = { type: AST.BinaryExpression, operator: token.text, left: left, right: this.unary() };
22166     }
22167     return left;
22168   },
22169
22170   unary: function() {
22171     var token;
22172     if ((token = this.expect('+', '-', '!'))) {
22173       return { type: AST.UnaryExpression, operator: token.text, prefix: true, argument: this.unary() };
22174     } else {
22175       return this.primary();
22176     }
22177   },
22178
22179   primary: function() {
22180     var primary;
22181     if (this.expect('(')) {
22182       primary = this.filterChain();
22183       this.consume(')');
22184     } else if (this.expect('[')) {
22185       primary = this.arrayDeclaration();
22186     } else if (this.expect('{')) {
22187       primary = this.object();
22188     } else if (this.constants.hasOwnProperty(this.peek().text)) {
22189       primary = copy(this.constants[this.consume().text]);
22190     } else if (this.peek().identifier) {
22191       primary = this.identifier();
22192     } else if (this.peek().constant) {
22193       primary = this.constant();
22194     } else {
22195       this.throwError('not a primary expression', this.peek());
22196     }
22197
22198     var next;
22199     while ((next = this.expect('(', '[', '.'))) {
22200       if (next.text === '(') {
22201         primary = {type: AST.CallExpression, callee: primary, arguments: this.parseArguments() };
22202         this.consume(')');
22203       } else if (next.text === '[') {
22204         primary = { type: AST.MemberExpression, object: primary, property: this.expression(), computed: true };
22205         this.consume(']');
22206       } else if (next.text === '.') {
22207         primary = { type: AST.MemberExpression, object: primary, property: this.identifier(), computed: false };
22208       } else {
22209         this.throwError('IMPOSSIBLE');
22210       }
22211     }
22212     return primary;
22213   },
22214
22215   filter: function(baseExpression) {
22216     var args = [baseExpression];
22217     var result = {type: AST.CallExpression, callee: this.identifier(), arguments: args, filter: true};
22218
22219     while (this.expect(':')) {
22220       args.push(this.expression());
22221     }
22222
22223     return result;
22224   },
22225
22226   parseArguments: function() {
22227     var args = [];
22228     if (this.peekToken().text !== ')') {
22229       do {
22230         args.push(this.expression());
22231       } while (this.expect(','));
22232     }
22233     return args;
22234   },
22235
22236   identifier: function() {
22237     var token = this.consume();
22238     if (!token.identifier) {
22239       this.throwError('is not a valid identifier', token);
22240     }
22241     return { type: AST.Identifier, name: token.text };
22242   },
22243
22244   constant: function() {
22245     // TODO check that it is a constant
22246     return { type: AST.Literal, value: this.consume().value };
22247   },
22248
22249   arrayDeclaration: function() {
22250     var elements = [];
22251     if (this.peekToken().text !== ']') {
22252       do {
22253         if (this.peek(']')) {
22254           // Support trailing commas per ES5.1.
22255           break;
22256         }
22257         elements.push(this.expression());
22258       } while (this.expect(','));
22259     }
22260     this.consume(']');
22261
22262     return { type: AST.ArrayExpression, elements: elements };
22263   },
22264
22265   object: function() {
22266     var properties = [], property;
22267     if (this.peekToken().text !== '}') {
22268       do {
22269         if (this.peek('}')) {
22270           // Support trailing commas per ES5.1.
22271           break;
22272         }
22273         property = {type: AST.Property, kind: 'init'};
22274         if (this.peek().constant) {
22275           property.key = this.constant();
22276         } else if (this.peek().identifier) {
22277           property.key = this.identifier();
22278         } else {
22279           this.throwError("invalid key", this.peek());
22280         }
22281         this.consume(':');
22282         property.value = this.expression();
22283         properties.push(property);
22284       } while (this.expect(','));
22285     }
22286     this.consume('}');
22287
22288     return {type: AST.ObjectExpression, properties: properties };
22289   },
22290
22291   throwError: function(msg, token) {
22292     throw $parseMinErr('syntax',
22293         'Syntax Error: Token \'{0}\' {1} at column {2} of the expression [{3}] starting at [{4}].',
22294           token.text, msg, (token.index + 1), this.text, this.text.substring(token.index));
22295   },
22296
22297   consume: function(e1) {
22298     if (this.tokens.length === 0) {
22299       throw $parseMinErr('ueoe', 'Unexpected end of expression: {0}', this.text);
22300     }
22301
22302     var token = this.expect(e1);
22303     if (!token) {
22304       this.throwError('is unexpected, expecting [' + e1 + ']', this.peek());
22305     }
22306     return token;
22307   },
22308
22309   peekToken: function() {
22310     if (this.tokens.length === 0) {
22311       throw $parseMinErr('ueoe', 'Unexpected end of expression: {0}', this.text);
22312     }
22313     return this.tokens[0];
22314   },
22315
22316   peek: function(e1, e2, e3, e4) {
22317     return this.peekAhead(0, e1, e2, e3, e4);
22318   },
22319
22320   peekAhead: function(i, e1, e2, e3, e4) {
22321     if (this.tokens.length > i) {
22322       var token = this.tokens[i];
22323       var t = token.text;
22324       if (t === e1 || t === e2 || t === e3 || t === e4 ||
22325           (!e1 && !e2 && !e3 && !e4)) {
22326         return token;
22327       }
22328     }
22329     return false;
22330   },
22331
22332   expect: function(e1, e2, e3, e4) {
22333     var token = this.peek(e1, e2, e3, e4);
22334     if (token) {
22335       this.tokens.shift();
22336       return token;
22337     }
22338     return false;
22339   },
22340
22341
22342   /* `undefined` is not a constant, it is an identifier,
22343    * but using it as an identifier is not supported
22344    */
22345   constants: {
22346     'true': { type: AST.Literal, value: true },
22347     'false': { type: AST.Literal, value: false },
22348     'null': { type: AST.Literal, value: null },
22349     'undefined': {type: AST.Literal, value: undefined },
22350     'this': {type: AST.ThisExpression }
22351   }
22352 };
22353
22354 function ifDefined(v, d) {
22355   return typeof v !== 'undefined' ? v : d;
22356 }
22357
22358 function plusFn(l, r) {
22359   if (typeof l === 'undefined') return r;
22360   if (typeof r === 'undefined') return l;
22361   return l + r;
22362 }
22363
22364 function isStateless($filter, filterName) {
22365   var fn = $filter(filterName);
22366   return !fn.$stateful;
22367 }
22368
22369 function findConstantAndWatchExpressions(ast, $filter) {
22370   var allConstants;
22371   var argsToWatch;
22372   switch (ast.type) {
22373   case AST.Program:
22374     allConstants = true;
22375     forEach(ast.body, function(expr) {
22376       findConstantAndWatchExpressions(expr.expression, $filter);
22377       allConstants = allConstants && expr.expression.constant;
22378     });
22379     ast.constant = allConstants;
22380     break;
22381   case AST.Literal:
22382     ast.constant = true;
22383     ast.toWatch = [];
22384     break;
22385   case AST.UnaryExpression:
22386     findConstantAndWatchExpressions(ast.argument, $filter);
22387     ast.constant = ast.argument.constant;
22388     ast.toWatch = ast.argument.toWatch;
22389     break;
22390   case AST.BinaryExpression:
22391     findConstantAndWatchExpressions(ast.left, $filter);
22392     findConstantAndWatchExpressions(ast.right, $filter);
22393     ast.constant = ast.left.constant && ast.right.constant;
22394     ast.toWatch = ast.left.toWatch.concat(ast.right.toWatch);
22395     break;
22396   case AST.LogicalExpression:
22397     findConstantAndWatchExpressions(ast.left, $filter);
22398     findConstantAndWatchExpressions(ast.right, $filter);
22399     ast.constant = ast.left.constant && ast.right.constant;
22400     ast.toWatch = ast.constant ? [] : [ast];
22401     break;
22402   case AST.ConditionalExpression:
22403     findConstantAndWatchExpressions(ast.test, $filter);
22404     findConstantAndWatchExpressions(ast.alternate, $filter);
22405     findConstantAndWatchExpressions(ast.consequent, $filter);
22406     ast.constant = ast.test.constant && ast.alternate.constant && ast.consequent.constant;
22407     ast.toWatch = ast.constant ? [] : [ast];
22408     break;
22409   case AST.Identifier:
22410     ast.constant = false;
22411     ast.toWatch = [ast];
22412     break;
22413   case AST.MemberExpression:
22414     findConstantAndWatchExpressions(ast.object, $filter);
22415     if (ast.computed) {
22416       findConstantAndWatchExpressions(ast.property, $filter);
22417     }
22418     ast.constant = ast.object.constant && (!ast.computed || ast.property.constant);
22419     ast.toWatch = [ast];
22420     break;
22421   case AST.CallExpression:
22422     allConstants = ast.filter ? isStateless($filter, ast.callee.name) : false;
22423     argsToWatch = [];
22424     forEach(ast.arguments, function(expr) {
22425       findConstantAndWatchExpressions(expr, $filter);
22426       allConstants = allConstants && expr.constant;
22427       if (!expr.constant) {
22428         argsToWatch.push.apply(argsToWatch, expr.toWatch);
22429       }
22430     });
22431     ast.constant = allConstants;
22432     ast.toWatch = ast.filter && isStateless($filter, ast.callee.name) ? argsToWatch : [ast];
22433     break;
22434   case AST.AssignmentExpression:
22435     findConstantAndWatchExpressions(ast.left, $filter);
22436     findConstantAndWatchExpressions(ast.right, $filter);
22437     ast.constant = ast.left.constant && ast.right.constant;
22438     ast.toWatch = [ast];
22439     break;
22440   case AST.ArrayExpression:
22441     allConstants = true;
22442     argsToWatch = [];
22443     forEach(ast.elements, function(expr) {
22444       findConstantAndWatchExpressions(expr, $filter);
22445       allConstants = allConstants && expr.constant;
22446       if (!expr.constant) {
22447         argsToWatch.push.apply(argsToWatch, expr.toWatch);
22448       }
22449     });
22450     ast.constant = allConstants;
22451     ast.toWatch = argsToWatch;
22452     break;
22453   case AST.ObjectExpression:
22454     allConstants = true;
22455     argsToWatch = [];
22456     forEach(ast.properties, function(property) {
22457       findConstantAndWatchExpressions(property.value, $filter);
22458       allConstants = allConstants && property.value.constant;
22459       if (!property.value.constant) {
22460         argsToWatch.push.apply(argsToWatch, property.value.toWatch);
22461       }
22462     });
22463     ast.constant = allConstants;
22464     ast.toWatch = argsToWatch;
22465     break;
22466   case AST.ThisExpression:
22467     ast.constant = false;
22468     ast.toWatch = [];
22469     break;
22470   }
22471 }
22472
22473 function getInputs(body) {
22474   if (body.length != 1) return;
22475   var lastExpression = body[0].expression;
22476   var candidate = lastExpression.toWatch;
22477   if (candidate.length !== 1) return candidate;
22478   return candidate[0] !== lastExpression ? candidate : undefined;
22479 }
22480
22481 function isAssignable(ast) {
22482   return ast.type === AST.Identifier || ast.type === AST.MemberExpression;
22483 }
22484
22485 function assignableAST(ast) {
22486   if (ast.body.length === 1 && isAssignable(ast.body[0].expression)) {
22487     return {type: AST.AssignmentExpression, left: ast.body[0].expression, right: {type: AST.NGValueParameter}, operator: '='};
22488   }
22489 }
22490
22491 function isLiteral(ast) {
22492   return ast.body.length === 0 ||
22493       ast.body.length === 1 && (
22494       ast.body[0].expression.type === AST.Literal ||
22495       ast.body[0].expression.type === AST.ArrayExpression ||
22496       ast.body[0].expression.type === AST.ObjectExpression);
22497 }
22498
22499 function isConstant(ast) {
22500   return ast.constant;
22501 }
22502
22503 function ASTCompiler(astBuilder, $filter) {
22504   this.astBuilder = astBuilder;
22505   this.$filter = $filter;
22506 }
22507
22508 ASTCompiler.prototype = {
22509   compile: function(expression, expensiveChecks) {
22510     var self = this;
22511     var ast = this.astBuilder.ast(expression);
22512     this.state = {
22513       nextId: 0,
22514       filters: {},
22515       expensiveChecks: expensiveChecks,
22516       fn: {vars: [], body: [], own: {}},
22517       assign: {vars: [], body: [], own: {}},
22518       inputs: []
22519     };
22520     findConstantAndWatchExpressions(ast, self.$filter);
22521     var extra = '';
22522     var assignable;
22523     this.stage = 'assign';
22524     if ((assignable = assignableAST(ast))) {
22525       this.state.computing = 'assign';
22526       var result = this.nextId();
22527       this.recurse(assignable, result);
22528       this.return_(result);
22529       extra = 'fn.assign=' + this.generateFunction('assign', 's,v,l');
22530     }
22531     var toWatch = getInputs(ast.body);
22532     self.stage = 'inputs';
22533     forEach(toWatch, function(watch, key) {
22534       var fnKey = 'fn' + key;
22535       self.state[fnKey] = {vars: [], body: [], own: {}};
22536       self.state.computing = fnKey;
22537       var intoId = self.nextId();
22538       self.recurse(watch, intoId);
22539       self.return_(intoId);
22540       self.state.inputs.push(fnKey);
22541       watch.watchId = key;
22542     });
22543     this.state.computing = 'fn';
22544     this.stage = 'main';
22545     this.recurse(ast);
22546     var fnString =
22547       // The build and minification steps remove the string "use strict" from the code, but this is done using a regex.
22548       // This is a workaround for this until we do a better job at only removing the prefix only when we should.
22549       '"' + this.USE + ' ' + this.STRICT + '";\n' +
22550       this.filterPrefix() +
22551       'var fn=' + this.generateFunction('fn', 's,l,a,i') +
22552       extra +
22553       this.watchFns() +
22554       'return fn;';
22555
22556     /* jshint -W054 */
22557     var fn = (new Function('$filter',
22558         'ensureSafeMemberName',
22559         'ensureSafeObject',
22560         'ensureSafeFunction',
22561         'getStringValue',
22562         'ensureSafeAssignContext',
22563         'ifDefined',
22564         'plus',
22565         'text',
22566         fnString))(
22567           this.$filter,
22568           ensureSafeMemberName,
22569           ensureSafeObject,
22570           ensureSafeFunction,
22571           getStringValue,
22572           ensureSafeAssignContext,
22573           ifDefined,
22574           plusFn,
22575           expression);
22576     /* jshint +W054 */
22577     this.state = this.stage = undefined;
22578     fn.literal = isLiteral(ast);
22579     fn.constant = isConstant(ast);
22580     return fn;
22581   },
22582
22583   USE: 'use',
22584
22585   STRICT: 'strict',
22586
22587   watchFns: function() {
22588     var result = [];
22589     var fns = this.state.inputs;
22590     var self = this;
22591     forEach(fns, function(name) {
22592       result.push('var ' + name + '=' + self.generateFunction(name, 's'));
22593     });
22594     if (fns.length) {
22595       result.push('fn.inputs=[' + fns.join(',') + '];');
22596     }
22597     return result.join('');
22598   },
22599
22600   generateFunction: function(name, params) {
22601     return 'function(' + params + '){' +
22602         this.varsPrefix(name) +
22603         this.body(name) +
22604         '};';
22605   },
22606
22607   filterPrefix: function() {
22608     var parts = [];
22609     var self = this;
22610     forEach(this.state.filters, function(id, filter) {
22611       parts.push(id + '=$filter(' + self.escape(filter) + ')');
22612     });
22613     if (parts.length) return 'var ' + parts.join(',') + ';';
22614     return '';
22615   },
22616
22617   varsPrefix: function(section) {
22618     return this.state[section].vars.length ? 'var ' + this.state[section].vars.join(',') + ';' : '';
22619   },
22620
22621   body: function(section) {
22622     return this.state[section].body.join('');
22623   },
22624
22625   recurse: function(ast, intoId, nameId, recursionFn, create, skipWatchIdCheck) {
22626     var left, right, self = this, args, expression;
22627     recursionFn = recursionFn || noop;
22628     if (!skipWatchIdCheck && isDefined(ast.watchId)) {
22629       intoId = intoId || this.nextId();
22630       this.if_('i',
22631         this.lazyAssign(intoId, this.computedMember('i', ast.watchId)),
22632         this.lazyRecurse(ast, intoId, nameId, recursionFn, create, true)
22633       );
22634       return;
22635     }
22636     switch (ast.type) {
22637     case AST.Program:
22638       forEach(ast.body, function(expression, pos) {
22639         self.recurse(expression.expression, undefined, undefined, function(expr) { right = expr; });
22640         if (pos !== ast.body.length - 1) {
22641           self.current().body.push(right, ';');
22642         } else {
22643           self.return_(right);
22644         }
22645       });
22646       break;
22647     case AST.Literal:
22648       expression = this.escape(ast.value);
22649       this.assign(intoId, expression);
22650       recursionFn(expression);
22651       break;
22652     case AST.UnaryExpression:
22653       this.recurse(ast.argument, undefined, undefined, function(expr) { right = expr; });
22654       expression = ast.operator + '(' + this.ifDefined(right, 0) + ')';
22655       this.assign(intoId, expression);
22656       recursionFn(expression);
22657       break;
22658     case AST.BinaryExpression:
22659       this.recurse(ast.left, undefined, undefined, function(expr) { left = expr; });
22660       this.recurse(ast.right, undefined, undefined, function(expr) { right = expr; });
22661       if (ast.operator === '+') {
22662         expression = this.plus(left, right);
22663       } else if (ast.operator === '-') {
22664         expression = this.ifDefined(left, 0) + ast.operator + this.ifDefined(right, 0);
22665       } else {
22666         expression = '(' + left + ')' + ast.operator + '(' + right + ')';
22667       }
22668       this.assign(intoId, expression);
22669       recursionFn(expression);
22670       break;
22671     case AST.LogicalExpression:
22672       intoId = intoId || this.nextId();
22673       self.recurse(ast.left, intoId);
22674       self.if_(ast.operator === '&&' ? intoId : self.not(intoId), self.lazyRecurse(ast.right, intoId));
22675       recursionFn(intoId);
22676       break;
22677     case AST.ConditionalExpression:
22678       intoId = intoId || this.nextId();
22679       self.recurse(ast.test, intoId);
22680       self.if_(intoId, self.lazyRecurse(ast.alternate, intoId), self.lazyRecurse(ast.consequent, intoId));
22681       recursionFn(intoId);
22682       break;
22683     case AST.Identifier:
22684       intoId = intoId || this.nextId();
22685       if (nameId) {
22686         nameId.context = self.stage === 'inputs' ? 's' : this.assign(this.nextId(), this.getHasOwnProperty('l', ast.name) + '?l:s');
22687         nameId.computed = false;
22688         nameId.name = ast.name;
22689       }
22690       ensureSafeMemberName(ast.name);
22691       self.if_(self.stage === 'inputs' || self.not(self.getHasOwnProperty('l', ast.name)),
22692         function() {
22693           self.if_(self.stage === 'inputs' || 's', function() {
22694             if (create && create !== 1) {
22695               self.if_(
22696                 self.not(self.nonComputedMember('s', ast.name)),
22697                 self.lazyAssign(self.nonComputedMember('s', ast.name), '{}'));
22698             }
22699             self.assign(intoId, self.nonComputedMember('s', ast.name));
22700           });
22701         }, intoId && self.lazyAssign(intoId, self.nonComputedMember('l', ast.name))
22702         );
22703       if (self.state.expensiveChecks || isPossiblyDangerousMemberName(ast.name)) {
22704         self.addEnsureSafeObject(intoId);
22705       }
22706       recursionFn(intoId);
22707       break;
22708     case AST.MemberExpression:
22709       left = nameId && (nameId.context = this.nextId()) || this.nextId();
22710       intoId = intoId || this.nextId();
22711       self.recurse(ast.object, left, undefined, function() {
22712         self.if_(self.notNull(left), function() {
22713           if (ast.computed) {
22714             right = self.nextId();
22715             self.recurse(ast.property, right);
22716             self.getStringValue(right);
22717             self.addEnsureSafeMemberName(right);
22718             if (create && create !== 1) {
22719               self.if_(self.not(self.computedMember(left, right)), self.lazyAssign(self.computedMember(left, right), '{}'));
22720             }
22721             expression = self.ensureSafeObject(self.computedMember(left, right));
22722             self.assign(intoId, expression);
22723             if (nameId) {
22724               nameId.computed = true;
22725               nameId.name = right;
22726             }
22727           } else {
22728             ensureSafeMemberName(ast.property.name);
22729             if (create && create !== 1) {
22730               self.if_(self.not(self.nonComputedMember(left, ast.property.name)), self.lazyAssign(self.nonComputedMember(left, ast.property.name), '{}'));
22731             }
22732             expression = self.nonComputedMember(left, ast.property.name);
22733             if (self.state.expensiveChecks || isPossiblyDangerousMemberName(ast.property.name)) {
22734               expression = self.ensureSafeObject(expression);
22735             }
22736             self.assign(intoId, expression);
22737             if (nameId) {
22738               nameId.computed = false;
22739               nameId.name = ast.property.name;
22740             }
22741           }
22742         }, function() {
22743           self.assign(intoId, 'undefined');
22744         });
22745         recursionFn(intoId);
22746       }, !!create);
22747       break;
22748     case AST.CallExpression:
22749       intoId = intoId || this.nextId();
22750       if (ast.filter) {
22751         right = self.filter(ast.callee.name);
22752         args = [];
22753         forEach(ast.arguments, function(expr) {
22754           var argument = self.nextId();
22755           self.recurse(expr, argument);
22756           args.push(argument);
22757         });
22758         expression = right + '(' + args.join(',') + ')';
22759         self.assign(intoId, expression);
22760         recursionFn(intoId);
22761       } else {
22762         right = self.nextId();
22763         left = {};
22764         args = [];
22765         self.recurse(ast.callee, right, left, function() {
22766           self.if_(self.notNull(right), function() {
22767             self.addEnsureSafeFunction(right);
22768             forEach(ast.arguments, function(expr) {
22769               self.recurse(expr, self.nextId(), undefined, function(argument) {
22770                 args.push(self.ensureSafeObject(argument));
22771               });
22772             });
22773             if (left.name) {
22774               if (!self.state.expensiveChecks) {
22775                 self.addEnsureSafeObject(left.context);
22776               }
22777               expression = self.member(left.context, left.name, left.computed) + '(' + args.join(',') + ')';
22778             } else {
22779               expression = right + '(' + args.join(',') + ')';
22780             }
22781             expression = self.ensureSafeObject(expression);
22782             self.assign(intoId, expression);
22783           }, function() {
22784             self.assign(intoId, 'undefined');
22785           });
22786           recursionFn(intoId);
22787         });
22788       }
22789       break;
22790     case AST.AssignmentExpression:
22791       right = this.nextId();
22792       left = {};
22793       if (!isAssignable(ast.left)) {
22794         throw $parseMinErr('lval', 'Trying to assing a value to a non l-value');
22795       }
22796       this.recurse(ast.left, undefined, left, function() {
22797         self.if_(self.notNull(left.context), function() {
22798           self.recurse(ast.right, right);
22799           self.addEnsureSafeObject(self.member(left.context, left.name, left.computed));
22800           self.addEnsureSafeAssignContext(left.context);
22801           expression = self.member(left.context, left.name, left.computed) + ast.operator + right;
22802           self.assign(intoId, expression);
22803           recursionFn(intoId || expression);
22804         });
22805       }, 1);
22806       break;
22807     case AST.ArrayExpression:
22808       args = [];
22809       forEach(ast.elements, function(expr) {
22810         self.recurse(expr, self.nextId(), undefined, function(argument) {
22811           args.push(argument);
22812         });
22813       });
22814       expression = '[' + args.join(',') + ']';
22815       this.assign(intoId, expression);
22816       recursionFn(expression);
22817       break;
22818     case AST.ObjectExpression:
22819       args = [];
22820       forEach(ast.properties, function(property) {
22821         self.recurse(property.value, self.nextId(), undefined, function(expr) {
22822           args.push(self.escape(
22823               property.key.type === AST.Identifier ? property.key.name :
22824                 ('' + property.key.value)) +
22825               ':' + expr);
22826         });
22827       });
22828       expression = '{' + args.join(',') + '}';
22829       this.assign(intoId, expression);
22830       recursionFn(expression);
22831       break;
22832     case AST.ThisExpression:
22833       this.assign(intoId, 's');
22834       recursionFn('s');
22835       break;
22836     case AST.NGValueParameter:
22837       this.assign(intoId, 'v');
22838       recursionFn('v');
22839       break;
22840     }
22841   },
22842
22843   getHasOwnProperty: function(element, property) {
22844     var key = element + '.' + property;
22845     var own = this.current().own;
22846     if (!own.hasOwnProperty(key)) {
22847       own[key] = this.nextId(false, element + '&&(' + this.escape(property) + ' in ' + element + ')');
22848     }
22849     return own[key];
22850   },
22851
22852   assign: function(id, value) {
22853     if (!id) return;
22854     this.current().body.push(id, '=', value, ';');
22855     return id;
22856   },
22857
22858   filter: function(filterName) {
22859     if (!this.state.filters.hasOwnProperty(filterName)) {
22860       this.state.filters[filterName] = this.nextId(true);
22861     }
22862     return this.state.filters[filterName];
22863   },
22864
22865   ifDefined: function(id, defaultValue) {
22866     return 'ifDefined(' + id + ',' + this.escape(defaultValue) + ')';
22867   },
22868
22869   plus: function(left, right) {
22870     return 'plus(' + left + ',' + right + ')';
22871   },
22872
22873   return_: function(id) {
22874     this.current().body.push('return ', id, ';');
22875   },
22876
22877   if_: function(test, alternate, consequent) {
22878     if (test === true) {
22879       alternate();
22880     } else {
22881       var body = this.current().body;
22882       body.push('if(', test, '){');
22883       alternate();
22884       body.push('}');
22885       if (consequent) {
22886         body.push('else{');
22887         consequent();
22888         body.push('}');
22889       }
22890     }
22891   },
22892
22893   not: function(expression) {
22894     return '!(' + expression + ')';
22895   },
22896
22897   notNull: function(expression) {
22898     return expression + '!=null';
22899   },
22900
22901   nonComputedMember: function(left, right) {
22902     return left + '.' + right;
22903   },
22904
22905   computedMember: function(left, right) {
22906     return left + '[' + right + ']';
22907   },
22908
22909   member: function(left, right, computed) {
22910     if (computed) return this.computedMember(left, right);
22911     return this.nonComputedMember(left, right);
22912   },
22913
22914   addEnsureSafeObject: function(item) {
22915     this.current().body.push(this.ensureSafeObject(item), ';');
22916   },
22917
22918   addEnsureSafeMemberName: function(item) {
22919     this.current().body.push(this.ensureSafeMemberName(item), ';');
22920   },
22921
22922   addEnsureSafeFunction: function(item) {
22923     this.current().body.push(this.ensureSafeFunction(item), ';');
22924   },
22925
22926   addEnsureSafeAssignContext: function(item) {
22927     this.current().body.push(this.ensureSafeAssignContext(item), ';');
22928   },
22929
22930   ensureSafeObject: function(item) {
22931     return 'ensureSafeObject(' + item + ',text)';
22932   },
22933
22934   ensureSafeMemberName: function(item) {
22935     return 'ensureSafeMemberName(' + item + ',text)';
22936   },
22937
22938   ensureSafeFunction: function(item) {
22939     return 'ensureSafeFunction(' + item + ',text)';
22940   },
22941
22942   getStringValue: function(item) {
22943     this.assign(item, 'getStringValue(' + item + ',text)');
22944   },
22945
22946   ensureSafeAssignContext: function(item) {
22947     return 'ensureSafeAssignContext(' + item + ',text)';
22948   },
22949
22950   lazyRecurse: function(ast, intoId, nameId, recursionFn, create, skipWatchIdCheck) {
22951     var self = this;
22952     return function() {
22953       self.recurse(ast, intoId, nameId, recursionFn, create, skipWatchIdCheck);
22954     };
22955   },
22956
22957   lazyAssign: function(id, value) {
22958     var self = this;
22959     return function() {
22960       self.assign(id, value);
22961     };
22962   },
22963
22964   stringEscapeRegex: /[^ a-zA-Z0-9]/g,
22965
22966   stringEscapeFn: function(c) {
22967     return '\\u' + ('0000' + c.charCodeAt(0).toString(16)).slice(-4);
22968   },
22969
22970   escape: function(value) {
22971     if (isString(value)) return "'" + value.replace(this.stringEscapeRegex, this.stringEscapeFn) + "'";
22972     if (isNumber(value)) return value.toString();
22973     if (value === true) return 'true';
22974     if (value === false) return 'false';
22975     if (value === null) return 'null';
22976     if (typeof value === 'undefined') return 'undefined';
22977
22978     throw $parseMinErr('esc', 'IMPOSSIBLE');
22979   },
22980
22981   nextId: function(skip, init) {
22982     var id = 'v' + (this.state.nextId++);
22983     if (!skip) {
22984       this.current().vars.push(id + (init ? '=' + init : ''));
22985     }
22986     return id;
22987   },
22988
22989   current: function() {
22990     return this.state[this.state.computing];
22991   }
22992 };
22993
22994
22995 function ASTInterpreter(astBuilder, $filter) {
22996   this.astBuilder = astBuilder;
22997   this.$filter = $filter;
22998 }
22999
23000 ASTInterpreter.prototype = {
23001   compile: function(expression, expensiveChecks) {
23002     var self = this;
23003     var ast = this.astBuilder.ast(expression);
23004     this.expression = expression;
23005     this.expensiveChecks = expensiveChecks;
23006     findConstantAndWatchExpressions(ast, self.$filter);
23007     var assignable;
23008     var assign;
23009     if ((assignable = assignableAST(ast))) {
23010       assign = this.recurse(assignable);
23011     }
23012     var toWatch = getInputs(ast.body);
23013     var inputs;
23014     if (toWatch) {
23015       inputs = [];
23016       forEach(toWatch, function(watch, key) {
23017         var input = self.recurse(watch);
23018         watch.input = input;
23019         inputs.push(input);
23020         watch.watchId = key;
23021       });
23022     }
23023     var expressions = [];
23024     forEach(ast.body, function(expression) {
23025       expressions.push(self.recurse(expression.expression));
23026     });
23027     var fn = ast.body.length === 0 ? function() {} :
23028              ast.body.length === 1 ? expressions[0] :
23029              function(scope, locals) {
23030                var lastValue;
23031                forEach(expressions, function(exp) {
23032                  lastValue = exp(scope, locals);
23033                });
23034                return lastValue;
23035              };
23036     if (assign) {
23037       fn.assign = function(scope, value, locals) {
23038         return assign(scope, locals, value);
23039       };
23040     }
23041     if (inputs) {
23042       fn.inputs = inputs;
23043     }
23044     fn.literal = isLiteral(ast);
23045     fn.constant = isConstant(ast);
23046     return fn;
23047   },
23048
23049   recurse: function(ast, context, create) {
23050     var left, right, self = this, args, expression;
23051     if (ast.input) {
23052       return this.inputs(ast.input, ast.watchId);
23053     }
23054     switch (ast.type) {
23055     case AST.Literal:
23056       return this.value(ast.value, context);
23057     case AST.UnaryExpression:
23058       right = this.recurse(ast.argument);
23059       return this['unary' + ast.operator](right, context);
23060     case AST.BinaryExpression:
23061       left = this.recurse(ast.left);
23062       right = this.recurse(ast.right);
23063       return this['binary' + ast.operator](left, right, context);
23064     case AST.LogicalExpression:
23065       left = this.recurse(ast.left);
23066       right = this.recurse(ast.right);
23067       return this['binary' + ast.operator](left, right, context);
23068     case AST.ConditionalExpression:
23069       return this['ternary?:'](
23070         this.recurse(ast.test),
23071         this.recurse(ast.alternate),
23072         this.recurse(ast.consequent),
23073         context
23074       );
23075     case AST.Identifier:
23076       ensureSafeMemberName(ast.name, self.expression);
23077       return self.identifier(ast.name,
23078                              self.expensiveChecks || isPossiblyDangerousMemberName(ast.name),
23079                              context, create, self.expression);
23080     case AST.MemberExpression:
23081       left = this.recurse(ast.object, false, !!create);
23082       if (!ast.computed) {
23083         ensureSafeMemberName(ast.property.name, self.expression);
23084         right = ast.property.name;
23085       }
23086       if (ast.computed) right = this.recurse(ast.property);
23087       return ast.computed ?
23088         this.computedMember(left, right, context, create, self.expression) :
23089         this.nonComputedMember(left, right, self.expensiveChecks, context, create, self.expression);
23090     case AST.CallExpression:
23091       args = [];
23092       forEach(ast.arguments, function(expr) {
23093         args.push(self.recurse(expr));
23094       });
23095       if (ast.filter) right = this.$filter(ast.callee.name);
23096       if (!ast.filter) right = this.recurse(ast.callee, true);
23097       return ast.filter ?
23098         function(scope, locals, assign, inputs) {
23099           var values = [];
23100           for (var i = 0; i < args.length; ++i) {
23101             values.push(args[i](scope, locals, assign, inputs));
23102           }
23103           var value = right.apply(undefined, values, inputs);
23104           return context ? {context: undefined, name: undefined, value: value} : value;
23105         } :
23106         function(scope, locals, assign, inputs) {
23107           var rhs = right(scope, locals, assign, inputs);
23108           var value;
23109           if (rhs.value != null) {
23110             ensureSafeObject(rhs.context, self.expression);
23111             ensureSafeFunction(rhs.value, self.expression);
23112             var values = [];
23113             for (var i = 0; i < args.length; ++i) {
23114               values.push(ensureSafeObject(args[i](scope, locals, assign, inputs), self.expression));
23115             }
23116             value = ensureSafeObject(rhs.value.apply(rhs.context, values), self.expression);
23117           }
23118           return context ? {value: value} : value;
23119         };
23120     case AST.AssignmentExpression:
23121       left = this.recurse(ast.left, true, 1);
23122       right = this.recurse(ast.right);
23123       return function(scope, locals, assign, inputs) {
23124         var lhs = left(scope, locals, assign, inputs);
23125         var rhs = right(scope, locals, assign, inputs);
23126         ensureSafeObject(lhs.value, self.expression);
23127         ensureSafeAssignContext(lhs.context);
23128         lhs.context[lhs.name] = rhs;
23129         return context ? {value: rhs} : rhs;
23130       };
23131     case AST.ArrayExpression:
23132       args = [];
23133       forEach(ast.elements, function(expr) {
23134         args.push(self.recurse(expr));
23135       });
23136       return function(scope, locals, assign, inputs) {
23137         var value = [];
23138         for (var i = 0; i < args.length; ++i) {
23139           value.push(args[i](scope, locals, assign, inputs));
23140         }
23141         return context ? {value: value} : value;
23142       };
23143     case AST.ObjectExpression:
23144       args = [];
23145       forEach(ast.properties, function(property) {
23146         args.push({key: property.key.type === AST.Identifier ?
23147                         property.key.name :
23148                         ('' + property.key.value),
23149                    value: self.recurse(property.value)
23150         });
23151       });
23152       return function(scope, locals, assign, inputs) {
23153         var value = {};
23154         for (var i = 0; i < args.length; ++i) {
23155           value[args[i].key] = args[i].value(scope, locals, assign, inputs);
23156         }
23157         return context ? {value: value} : value;
23158       };
23159     case AST.ThisExpression:
23160       return function(scope) {
23161         return context ? {value: scope} : scope;
23162       };
23163     case AST.NGValueParameter:
23164       return function(scope, locals, assign, inputs) {
23165         return context ? {value: assign} : assign;
23166       };
23167     }
23168   },
23169
23170   'unary+': function(argument, context) {
23171     return function(scope, locals, assign, inputs) {
23172       var arg = argument(scope, locals, assign, inputs);
23173       if (isDefined(arg)) {
23174         arg = +arg;
23175       } else {
23176         arg = 0;
23177       }
23178       return context ? {value: arg} : arg;
23179     };
23180   },
23181   'unary-': function(argument, context) {
23182     return function(scope, locals, assign, inputs) {
23183       var arg = argument(scope, locals, assign, inputs);
23184       if (isDefined(arg)) {
23185         arg = -arg;
23186       } else {
23187         arg = 0;
23188       }
23189       return context ? {value: arg} : arg;
23190     };
23191   },
23192   'unary!': function(argument, context) {
23193     return function(scope, locals, assign, inputs) {
23194       var arg = !argument(scope, locals, assign, inputs);
23195       return context ? {value: arg} : arg;
23196     };
23197   },
23198   'binary+': function(left, right, context) {
23199     return function(scope, locals, assign, inputs) {
23200       var lhs = left(scope, locals, assign, inputs);
23201       var rhs = right(scope, locals, assign, inputs);
23202       var arg = plusFn(lhs, rhs);
23203       return context ? {value: arg} : arg;
23204     };
23205   },
23206   'binary-': function(left, right, context) {
23207     return function(scope, locals, assign, inputs) {
23208       var lhs = left(scope, locals, assign, inputs);
23209       var rhs = right(scope, locals, assign, inputs);
23210       var arg = (isDefined(lhs) ? lhs : 0) - (isDefined(rhs) ? rhs : 0);
23211       return context ? {value: arg} : arg;
23212     };
23213   },
23214   'binary*': function(left, right, context) {
23215     return function(scope, locals, assign, inputs) {
23216       var arg = left(scope, locals, assign, inputs) * right(scope, locals, assign, inputs);
23217       return context ? {value: arg} : arg;
23218     };
23219   },
23220   'binary/': function(left, right, context) {
23221     return function(scope, locals, assign, inputs) {
23222       var arg = left(scope, locals, assign, inputs) / right(scope, locals, assign, inputs);
23223       return context ? {value: arg} : arg;
23224     };
23225   },
23226   'binary%': function(left, right, context) {
23227     return function(scope, locals, assign, inputs) {
23228       var arg = left(scope, locals, assign, inputs) % right(scope, locals, assign, inputs);
23229       return context ? {value: arg} : arg;
23230     };
23231   },
23232   'binary===': function(left, right, context) {
23233     return function(scope, locals, assign, inputs) {
23234       var arg = left(scope, locals, assign, inputs) === right(scope, locals, assign, inputs);
23235       return context ? {value: arg} : arg;
23236     };
23237   },
23238   'binary!==': function(left, right, context) {
23239     return function(scope, locals, assign, inputs) {
23240       var arg = left(scope, locals, assign, inputs) !== right(scope, locals, assign, inputs);
23241       return context ? {value: arg} : arg;
23242     };
23243   },
23244   'binary==': function(left, right, context) {
23245     return function(scope, locals, assign, inputs) {
23246       var arg = left(scope, locals, assign, inputs) == right(scope, locals, assign, inputs);
23247       return context ? {value: arg} : arg;
23248     };
23249   },
23250   'binary!=': function(left, right, context) {
23251     return function(scope, locals, assign, inputs) {
23252       var arg = left(scope, locals, assign, inputs) != right(scope, locals, assign, inputs);
23253       return context ? {value: arg} : arg;
23254     };
23255   },
23256   'binary<': function(left, right, context) {
23257     return function(scope, locals, assign, inputs) {
23258       var arg = left(scope, locals, assign, inputs) < right(scope, locals, assign, inputs);
23259       return context ? {value: arg} : arg;
23260     };
23261   },
23262   'binary>': function(left, right, context) {
23263     return function(scope, locals, assign, inputs) {
23264       var arg = left(scope, locals, assign, inputs) > right(scope, locals, assign, inputs);
23265       return context ? {value: arg} : arg;
23266     };
23267   },
23268   'binary<=': function(left, right, context) {
23269     return function(scope, locals, assign, inputs) {
23270       var arg = left(scope, locals, assign, inputs) <= right(scope, locals, assign, inputs);
23271       return context ? {value: arg} : arg;
23272     };
23273   },
23274   'binary>=': function(left, right, context) {
23275     return function(scope, locals, assign, inputs) {
23276       var arg = left(scope, locals, assign, inputs) >= right(scope, locals, assign, inputs);
23277       return context ? {value: arg} : arg;
23278     };
23279   },
23280   'binary&&': function(left, right, context) {
23281     return function(scope, locals, assign, inputs) {
23282       var arg = left(scope, locals, assign, inputs) && right(scope, locals, assign, inputs);
23283       return context ? {value: arg} : arg;
23284     };
23285   },
23286   'binary||': function(left, right, context) {
23287     return function(scope, locals, assign, inputs) {
23288       var arg = left(scope, locals, assign, inputs) || right(scope, locals, assign, inputs);
23289       return context ? {value: arg} : arg;
23290     };
23291   },
23292   'ternary?:': function(test, alternate, consequent, context) {
23293     return function(scope, locals, assign, inputs) {
23294       var arg = test(scope, locals, assign, inputs) ? alternate(scope, locals, assign, inputs) : consequent(scope, locals, assign, inputs);
23295       return context ? {value: arg} : arg;
23296     };
23297   },
23298   value: function(value, context) {
23299     return function() { return context ? {context: undefined, name: undefined, value: value} : value; };
23300   },
23301   identifier: function(name, expensiveChecks, context, create, expression) {
23302     return function(scope, locals, assign, inputs) {
23303       var base = locals && (name in locals) ? locals : scope;
23304       if (create && create !== 1 && base && !(base[name])) {
23305         base[name] = {};
23306       }
23307       var value = base ? base[name] : undefined;
23308       if (expensiveChecks) {
23309         ensureSafeObject(value, expression);
23310       }
23311       if (context) {
23312         return {context: base, name: name, value: value};
23313       } else {
23314         return value;
23315       }
23316     };
23317   },
23318   computedMember: function(left, right, context, create, expression) {
23319     return function(scope, locals, assign, inputs) {
23320       var lhs = left(scope, locals, assign, inputs);
23321       var rhs;
23322       var value;
23323       if (lhs != null) {
23324         rhs = right(scope, locals, assign, inputs);
23325         rhs = getStringValue(rhs);
23326         ensureSafeMemberName(rhs, expression);
23327         if (create && create !== 1 && lhs && !(lhs[rhs])) {
23328           lhs[rhs] = {};
23329         }
23330         value = lhs[rhs];
23331         ensureSafeObject(value, expression);
23332       }
23333       if (context) {
23334         return {context: lhs, name: rhs, value: value};
23335       } else {
23336         return value;
23337       }
23338     };
23339   },
23340   nonComputedMember: function(left, right, expensiveChecks, context, create, expression) {
23341     return function(scope, locals, assign, inputs) {
23342       var lhs = left(scope, locals, assign, inputs);
23343       if (create && create !== 1 && lhs && !(lhs[right])) {
23344         lhs[right] = {};
23345       }
23346       var value = lhs != null ? lhs[right] : undefined;
23347       if (expensiveChecks || isPossiblyDangerousMemberName(right)) {
23348         ensureSafeObject(value, expression);
23349       }
23350       if (context) {
23351         return {context: lhs, name: right, value: value};
23352       } else {
23353         return value;
23354       }
23355     };
23356   },
23357   inputs: function(input, watchId) {
23358     return function(scope, value, locals, inputs) {
23359       if (inputs) return inputs[watchId];
23360       return input(scope, value, locals);
23361     };
23362   }
23363 };
23364
23365 /**
23366  * @constructor
23367  */
23368 var Parser = function(lexer, $filter, options) {
23369   this.lexer = lexer;
23370   this.$filter = $filter;
23371   this.options = options;
23372   this.ast = new AST(this.lexer);
23373   this.astCompiler = options.csp ? new ASTInterpreter(this.ast, $filter) :
23374                                    new ASTCompiler(this.ast, $filter);
23375 };
23376
23377 Parser.prototype = {
23378   constructor: Parser,
23379
23380   parse: function(text) {
23381     return this.astCompiler.compile(text, this.options.expensiveChecks);
23382   }
23383 };
23384
23385 var getterFnCacheDefault = createMap();
23386 var getterFnCacheExpensive = createMap();
23387
23388 function isPossiblyDangerousMemberName(name) {
23389   return name == 'constructor';
23390 }
23391
23392 var objectValueOf = Object.prototype.valueOf;
23393
23394 function getValueOf(value) {
23395   return isFunction(value.valueOf) ? value.valueOf() : objectValueOf.call(value);
23396 }
23397
23398 ///////////////////////////////////
23399
23400 /**
23401  * @ngdoc service
23402  * @name $parse
23403  * @kind function
23404  *
23405  * @description
23406  *
23407  * Converts Angular {@link guide/expression expression} into a function.
23408  *
23409  * ```js
23410  *   var getter = $parse('user.name');
23411  *   var setter = getter.assign;
23412  *   var context = {user:{name:'angular'}};
23413  *   var locals = {user:{name:'local'}};
23414  *
23415  *   expect(getter(context)).toEqual('angular');
23416  *   setter(context, 'newValue');
23417  *   expect(context.user.name).toEqual('newValue');
23418  *   expect(getter(context, locals)).toEqual('local');
23419  * ```
23420  *
23421  *
23422  * @param {string} expression String expression to compile.
23423  * @returns {function(context, locals)} a function which represents the compiled expression:
23424  *
23425  *    * `context` – `{object}` – an object against which any expressions embedded in the strings
23426  *      are evaluated against (typically a scope object).
23427  *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
23428  *      `context`.
23429  *
23430  *    The returned function also has the following properties:
23431  *      * `literal` – `{boolean}` – whether the expression's top-level node is a JavaScript
23432  *        literal.
23433  *      * `constant` – `{boolean}` – whether the expression is made entirely of JavaScript
23434  *        constant literals.
23435  *      * `assign` – `{?function(context, value)}` – if the expression is assignable, this will be
23436  *        set to a function to change its value on the given context.
23437  *
23438  */
23439
23440
23441 /**
23442  * @ngdoc provider
23443  * @name $parseProvider
23444  *
23445  * @description
23446  * `$parseProvider` can be used for configuring the default behavior of the {@link ng.$parse $parse}
23447  *  service.
23448  */
23449 function $ParseProvider() {
23450   var cacheDefault = createMap();
23451   var cacheExpensive = createMap();
23452
23453   this.$get = ['$filter', function($filter) {
23454     var noUnsafeEval = csp().noUnsafeEval;
23455     var $parseOptions = {
23456           csp: noUnsafeEval,
23457           expensiveChecks: false
23458         },
23459         $parseOptionsExpensive = {
23460           csp: noUnsafeEval,
23461           expensiveChecks: true
23462         };
23463
23464     return function $parse(exp, interceptorFn, expensiveChecks) {
23465       var parsedExpression, oneTime, cacheKey;
23466
23467       switch (typeof exp) {
23468         case 'string':
23469           exp = exp.trim();
23470           cacheKey = exp;
23471
23472           var cache = (expensiveChecks ? cacheExpensive : cacheDefault);
23473           parsedExpression = cache[cacheKey];
23474
23475           if (!parsedExpression) {
23476             if (exp.charAt(0) === ':' && exp.charAt(1) === ':') {
23477               oneTime = true;
23478               exp = exp.substring(2);
23479             }
23480             var parseOptions = expensiveChecks ? $parseOptionsExpensive : $parseOptions;
23481             var lexer = new Lexer(parseOptions);
23482             var parser = new Parser(lexer, $filter, parseOptions);
23483             parsedExpression = parser.parse(exp);
23484             if (parsedExpression.constant) {
23485               parsedExpression.$$watchDelegate = constantWatchDelegate;
23486             } else if (oneTime) {
23487               parsedExpression.$$watchDelegate = parsedExpression.literal ?
23488                   oneTimeLiteralWatchDelegate : oneTimeWatchDelegate;
23489             } else if (parsedExpression.inputs) {
23490               parsedExpression.$$watchDelegate = inputsWatchDelegate;
23491             }
23492             cache[cacheKey] = parsedExpression;
23493           }
23494           return addInterceptor(parsedExpression, interceptorFn);
23495
23496         case 'function':
23497           return addInterceptor(exp, interceptorFn);
23498
23499         default:
23500           return noop;
23501       }
23502     };
23503
23504     function expressionInputDirtyCheck(newValue, oldValueOfValue) {
23505
23506       if (newValue == null || oldValueOfValue == null) { // null/undefined
23507         return newValue === oldValueOfValue;
23508       }
23509
23510       if (typeof newValue === 'object') {
23511
23512         // attempt to convert the value to a primitive type
23513         // TODO(docs): add a note to docs that by implementing valueOf even objects and arrays can
23514         //             be cheaply dirty-checked
23515         newValue = getValueOf(newValue);
23516
23517         if (typeof newValue === 'object') {
23518           // objects/arrays are not supported - deep-watching them would be too expensive
23519           return false;
23520         }
23521
23522         // fall-through to the primitive equality check
23523       }
23524
23525       //Primitive or NaN
23526       return newValue === oldValueOfValue || (newValue !== newValue && oldValueOfValue !== oldValueOfValue);
23527     }
23528
23529     function inputsWatchDelegate(scope, listener, objectEquality, parsedExpression, prettyPrintExpression) {
23530       var inputExpressions = parsedExpression.inputs;
23531       var lastResult;
23532
23533       if (inputExpressions.length === 1) {
23534         var oldInputValueOf = expressionInputDirtyCheck; // init to something unique so that equals check fails
23535         inputExpressions = inputExpressions[0];
23536         return scope.$watch(function expressionInputWatch(scope) {
23537           var newInputValue = inputExpressions(scope);
23538           if (!expressionInputDirtyCheck(newInputValue, oldInputValueOf)) {
23539             lastResult = parsedExpression(scope, undefined, undefined, [newInputValue]);
23540             oldInputValueOf = newInputValue && getValueOf(newInputValue);
23541           }
23542           return lastResult;
23543         }, listener, objectEquality, prettyPrintExpression);
23544       }
23545
23546       var oldInputValueOfValues = [];
23547       var oldInputValues = [];
23548       for (var i = 0, ii = inputExpressions.length; i < ii; i++) {
23549         oldInputValueOfValues[i] = expressionInputDirtyCheck; // init to something unique so that equals check fails
23550         oldInputValues[i] = null;
23551       }
23552
23553       return scope.$watch(function expressionInputsWatch(scope) {
23554         var changed = false;
23555
23556         for (var i = 0, ii = inputExpressions.length; i < ii; i++) {
23557           var newInputValue = inputExpressions[i](scope);
23558           if (changed || (changed = !expressionInputDirtyCheck(newInputValue, oldInputValueOfValues[i]))) {
23559             oldInputValues[i] = newInputValue;
23560             oldInputValueOfValues[i] = newInputValue && getValueOf(newInputValue);
23561           }
23562         }
23563
23564         if (changed) {
23565           lastResult = parsedExpression(scope, undefined, undefined, oldInputValues);
23566         }
23567
23568         return lastResult;
23569       }, listener, objectEquality, prettyPrintExpression);
23570     }
23571
23572     function oneTimeWatchDelegate(scope, listener, objectEquality, parsedExpression) {
23573       var unwatch, lastValue;
23574       return unwatch = scope.$watch(function oneTimeWatch(scope) {
23575         return parsedExpression(scope);
23576       }, function oneTimeListener(value, old, scope) {
23577         lastValue = value;
23578         if (isFunction(listener)) {
23579           listener.apply(this, arguments);
23580         }
23581         if (isDefined(value)) {
23582           scope.$$postDigest(function() {
23583             if (isDefined(lastValue)) {
23584               unwatch();
23585             }
23586           });
23587         }
23588       }, objectEquality);
23589     }
23590
23591     function oneTimeLiteralWatchDelegate(scope, listener, objectEquality, parsedExpression) {
23592       var unwatch, lastValue;
23593       return unwatch = scope.$watch(function oneTimeWatch(scope) {
23594         return parsedExpression(scope);
23595       }, function oneTimeListener(value, old, scope) {
23596         lastValue = value;
23597         if (isFunction(listener)) {
23598           listener.call(this, value, old, scope);
23599         }
23600         if (isAllDefined(value)) {
23601           scope.$$postDigest(function() {
23602             if (isAllDefined(lastValue)) unwatch();
23603           });
23604         }
23605       }, objectEquality);
23606
23607       function isAllDefined(value) {
23608         var allDefined = true;
23609         forEach(value, function(val) {
23610           if (!isDefined(val)) allDefined = false;
23611         });
23612         return allDefined;
23613       }
23614     }
23615
23616     function constantWatchDelegate(scope, listener, objectEquality, parsedExpression) {
23617       var unwatch;
23618       return unwatch = scope.$watch(function constantWatch(scope) {
23619         return parsedExpression(scope);
23620       }, function constantListener(value, old, scope) {
23621         if (isFunction(listener)) {
23622           listener.apply(this, arguments);
23623         }
23624         unwatch();
23625       }, objectEquality);
23626     }
23627
23628     function addInterceptor(parsedExpression, interceptorFn) {
23629       if (!interceptorFn) return parsedExpression;
23630       var watchDelegate = parsedExpression.$$watchDelegate;
23631       var useInputs = false;
23632
23633       var regularWatch =
23634           watchDelegate !== oneTimeLiteralWatchDelegate &&
23635           watchDelegate !== oneTimeWatchDelegate;
23636
23637       var fn = regularWatch ? function regularInterceptedExpression(scope, locals, assign, inputs) {
23638         var value = useInputs && inputs ? inputs[0] : parsedExpression(scope, locals, assign, inputs);
23639         return interceptorFn(value, scope, locals);
23640       } : function oneTimeInterceptedExpression(scope, locals, assign, inputs) {
23641         var value = parsedExpression(scope, locals, assign, inputs);
23642         var result = interceptorFn(value, scope, locals);
23643         // we only return the interceptor's result if the
23644         // initial value is defined (for bind-once)
23645         return isDefined(value) ? result : value;
23646       };
23647
23648       // Propagate $$watchDelegates other then inputsWatchDelegate
23649       if (parsedExpression.$$watchDelegate &&
23650           parsedExpression.$$watchDelegate !== inputsWatchDelegate) {
23651         fn.$$watchDelegate = parsedExpression.$$watchDelegate;
23652       } else if (!interceptorFn.$stateful) {
23653         // If there is an interceptor, but no watchDelegate then treat the interceptor like
23654         // we treat filters - it is assumed to be a pure function unless flagged with $stateful
23655         fn.$$watchDelegate = inputsWatchDelegate;
23656         useInputs = !parsedExpression.inputs;
23657         fn.inputs = parsedExpression.inputs ? parsedExpression.inputs : [parsedExpression];
23658       }
23659
23660       return fn;
23661     }
23662   }];
23663 }
23664
23665 /**
23666  * @ngdoc service
23667  * @name $q
23668  * @requires $rootScope
23669  *
23670  * @description
23671  * A service that helps you run functions asynchronously, and use their return values (or exceptions)
23672  * when they are done processing.
23673  *
23674  * This is an implementation of promises/deferred objects inspired by
23675  * [Kris Kowal's Q](https://github.com/kriskowal/q).
23676  *
23677  * $q can be used in two fashions --- one which is more similar to Kris Kowal's Q or jQuery's Deferred
23678  * implementations, and the other which resembles ES6 promises to some degree.
23679  *
23680  * # $q constructor
23681  *
23682  * The streamlined ES6 style promise is essentially just using $q as a constructor which takes a `resolver`
23683  * function as the first argument. This is similar to the native Promise implementation from ES6 Harmony,
23684  * see [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise).
23685  *
23686  * While the constructor-style use is supported, not all of the supporting methods from ES6 Harmony promises are
23687  * available yet.
23688  *
23689  * It can be used like so:
23690  *
23691  * ```js
23692  *   // for the purpose of this example let's assume that variables `$q` and `okToGreet`
23693  *   // are available in the current lexical scope (they could have been injected or passed in).
23694  *
23695  *   function asyncGreet(name) {
23696  *     // perform some asynchronous operation, resolve or reject the promise when appropriate.
23697  *     return $q(function(resolve, reject) {
23698  *       setTimeout(function() {
23699  *         if (okToGreet(name)) {
23700  *           resolve('Hello, ' + name + '!');
23701  *         } else {
23702  *           reject('Greeting ' + name + ' is not allowed.');
23703  *         }
23704  *       }, 1000);
23705  *     });
23706  *   }
23707  *
23708  *   var promise = asyncGreet('Robin Hood');
23709  *   promise.then(function(greeting) {
23710  *     alert('Success: ' + greeting);
23711  *   }, function(reason) {
23712  *     alert('Failed: ' + reason);
23713  *   });
23714  * ```
23715  *
23716  * Note: progress/notify callbacks are not currently supported via the ES6-style interface.
23717  *
23718  * Note: unlike ES6 behaviour, an exception thrown in the constructor function will NOT implicitly reject the promise.
23719  *
23720  * However, the more traditional CommonJS-style usage is still available, and documented below.
23721  *
23722  * [The CommonJS Promise proposal](http://wiki.commonjs.org/wiki/Promises) describes a promise as an
23723  * interface for interacting with an object that represents the result of an action that is
23724  * performed asynchronously, and may or may not be finished at any given point in time.
23725  *
23726  * From the perspective of dealing with error handling, deferred and promise APIs are to
23727  * asynchronous programming what `try`, `catch` and `throw` keywords are to synchronous programming.
23728  *
23729  * ```js
23730  *   // for the purpose of this example let's assume that variables `$q` and `okToGreet`
23731  *   // are available in the current lexical scope (they could have been injected or passed in).
23732  *
23733  *   function asyncGreet(name) {
23734  *     var deferred = $q.defer();
23735  *
23736  *     setTimeout(function() {
23737  *       deferred.notify('About to greet ' + name + '.');
23738  *
23739  *       if (okToGreet(name)) {
23740  *         deferred.resolve('Hello, ' + name + '!');
23741  *       } else {
23742  *         deferred.reject('Greeting ' + name + ' is not allowed.');
23743  *       }
23744  *     }, 1000);
23745  *
23746  *     return deferred.promise;
23747  *   }
23748  *
23749  *   var promise = asyncGreet('Robin Hood');
23750  *   promise.then(function(greeting) {
23751  *     alert('Success: ' + greeting);
23752  *   }, function(reason) {
23753  *     alert('Failed: ' + reason);
23754  *   }, function(update) {
23755  *     alert('Got notification: ' + update);
23756  *   });
23757  * ```
23758  *
23759  * At first it might not be obvious why this extra complexity is worth the trouble. The payoff
23760  * comes in the way of guarantees that promise and deferred APIs make, see
23761  * https://github.com/kriskowal/uncommonjs/blob/master/promises/specification.md.
23762  *
23763  * Additionally the promise api allows for composition that is very hard to do with the
23764  * traditional callback ([CPS](http://en.wikipedia.org/wiki/Continuation-passing_style)) approach.
23765  * For more on this please see the [Q documentation](https://github.com/kriskowal/q) especially the
23766  * section on serial or parallel joining of promises.
23767  *
23768  * # The Deferred API
23769  *
23770  * A new instance of deferred is constructed by calling `$q.defer()`.
23771  *
23772  * The purpose of the deferred object is to expose the associated Promise instance as well as APIs
23773  * that can be used for signaling the successful or unsuccessful completion, as well as the status
23774  * of the task.
23775  *
23776  * **Methods**
23777  *
23778  * - `resolve(value)` – resolves the derived promise with the `value`. If the value is a rejection
23779  *   constructed via `$q.reject`, the promise will be rejected instead.
23780  * - `reject(reason)` – rejects the derived promise with the `reason`. This is equivalent to
23781  *   resolving it with a rejection constructed via `$q.reject`.
23782  * - `notify(value)` - provides updates on the status of the promise's execution. This may be called
23783  *   multiple times before the promise is either resolved or rejected.
23784  *
23785  * **Properties**
23786  *
23787  * - promise – `{Promise}` – promise object associated with this deferred.
23788  *
23789  *
23790  * # The Promise API
23791  *
23792  * A new promise instance is created when a deferred instance is created and can be retrieved by
23793  * calling `deferred.promise`.
23794  *
23795  * The purpose of the promise object is to allow for interested parties to get access to the result
23796  * of the deferred task when it completes.
23797  *
23798  * **Methods**
23799  *
23800  * - `then(successCallback, errorCallback, notifyCallback)` – regardless of when the promise was or
23801  *   will be resolved or rejected, `then` calls one of the success or error callbacks asynchronously
23802  *   as soon as the result is available. The callbacks are called with a single argument: the result
23803  *   or rejection reason. Additionally, the notify callback may be called zero or more times to
23804  *   provide a progress indication, before the promise is resolved or rejected.
23805  *
23806  *   This method *returns a new promise* which is resolved or rejected via the return value of the
23807  *   `successCallback`, `errorCallback` (unless that value is a promise, in which case it is resolved
23808  *   with the value which is resolved in that promise using
23809  *   [promise chaining](http://www.html5rocks.com/en/tutorials/es6/promises/#toc-promises-queues)).
23810  *   It also notifies via the return value of the `notifyCallback` method. The promise cannot be
23811  *   resolved or rejected from the notifyCallback method.
23812  *
23813  * - `catch(errorCallback)` – shorthand for `promise.then(null, errorCallback)`
23814  *
23815  * - `finally(callback, notifyCallback)` – allows you to observe either the fulfillment or rejection of a promise,
23816  *   but to do so without modifying the final value. This is useful to release resources or do some
23817  *   clean-up that needs to be done whether the promise was rejected or resolved. See the [full
23818  *   specification](https://github.com/kriskowal/q/wiki/API-Reference#promisefinallycallback) for
23819  *   more information.
23820  *
23821  * # Chaining promises
23822  *
23823  * Because calling the `then` method of a promise returns a new derived promise, it is easily
23824  * possible to create a chain of promises:
23825  *
23826  * ```js
23827  *   promiseB = promiseA.then(function(result) {
23828  *     return result + 1;
23829  *   });
23830  *
23831  *   // promiseB will be resolved immediately after promiseA is resolved and its value
23832  *   // will be the result of promiseA incremented by 1
23833  * ```
23834  *
23835  * It is possible to create chains of any length and since a promise can be resolved with another
23836  * promise (which will defer its resolution further), it is possible to pause/defer resolution of
23837  * the promises at any point in the chain. This makes it possible to implement powerful APIs like
23838  * $http's response interceptors.
23839  *
23840  *
23841  * # Differences between Kris Kowal's Q and $q
23842  *
23843  *  There are two main differences:
23844  *
23845  * - $q is integrated with the {@link ng.$rootScope.Scope} Scope model observation
23846  *   mechanism in angular, which means faster propagation of resolution or rejection into your
23847  *   models and avoiding unnecessary browser repaints, which would result in flickering UI.
23848  * - Q has many more features than $q, but that comes at a cost of bytes. $q is tiny, but contains
23849  *   all the important functionality needed for common async tasks.
23850  *
23851  *  # Testing
23852  *
23853  *  ```js
23854  *    it('should simulate promise', inject(function($q, $rootScope) {
23855  *      var deferred = $q.defer();
23856  *      var promise = deferred.promise;
23857  *      var resolvedValue;
23858  *
23859  *      promise.then(function(value) { resolvedValue = value; });
23860  *      expect(resolvedValue).toBeUndefined();
23861  *
23862  *      // Simulate resolving of promise
23863  *      deferred.resolve(123);
23864  *      // Note that the 'then' function does not get called synchronously.
23865  *      // This is because we want the promise API to always be async, whether or not
23866  *      // it got called synchronously or asynchronously.
23867  *      expect(resolvedValue).toBeUndefined();
23868  *
23869  *      // Propagate promise resolution to 'then' functions using $apply().
23870  *      $rootScope.$apply();
23871  *      expect(resolvedValue).toEqual(123);
23872  *    }));
23873  *  ```
23874  *
23875  * @param {function(function, function)} resolver Function which is responsible for resolving or
23876  *   rejecting the newly created promise. The first parameter is a function which resolves the
23877  *   promise, the second parameter is a function which rejects the promise.
23878  *
23879  * @returns {Promise} The newly created promise.
23880  */
23881 function $QProvider() {
23882
23883   this.$get = ['$rootScope', '$exceptionHandler', function($rootScope, $exceptionHandler) {
23884     return qFactory(function(callback) {
23885       $rootScope.$evalAsync(callback);
23886     }, $exceptionHandler);
23887   }];
23888 }
23889
23890 function $$QProvider() {
23891   this.$get = ['$browser', '$exceptionHandler', function($browser, $exceptionHandler) {
23892     return qFactory(function(callback) {
23893       $browser.defer(callback);
23894     }, $exceptionHandler);
23895   }];
23896 }
23897
23898 /**
23899  * Constructs a promise manager.
23900  *
23901  * @param {function(function)} nextTick Function for executing functions in the next turn.
23902  * @param {function(...*)} exceptionHandler Function into which unexpected exceptions are passed for
23903  *     debugging purposes.
23904  * @returns {object} Promise manager.
23905  */
23906 function qFactory(nextTick, exceptionHandler) {
23907   var $qMinErr = minErr('$q', TypeError);
23908   function callOnce(self, resolveFn, rejectFn) {
23909     var called = false;
23910     function wrap(fn) {
23911       return function(value) {
23912         if (called) return;
23913         called = true;
23914         fn.call(self, value);
23915       };
23916     }
23917
23918     return [wrap(resolveFn), wrap(rejectFn)];
23919   }
23920
23921   /**
23922    * @ngdoc method
23923    * @name ng.$q#defer
23924    * @kind function
23925    *
23926    * @description
23927    * Creates a `Deferred` object which represents a task which will finish in the future.
23928    *
23929    * @returns {Deferred} Returns a new instance of deferred.
23930    */
23931   var defer = function() {
23932     return new Deferred();
23933   };
23934
23935   function Promise() {
23936     this.$$state = { status: 0 };
23937   }
23938
23939   extend(Promise.prototype, {
23940     then: function(onFulfilled, onRejected, progressBack) {
23941       if (isUndefined(onFulfilled) && isUndefined(onRejected) && isUndefined(progressBack)) {
23942         return this;
23943       }
23944       var result = new Deferred();
23945
23946       this.$$state.pending = this.$$state.pending || [];
23947       this.$$state.pending.push([result, onFulfilled, onRejected, progressBack]);
23948       if (this.$$state.status > 0) scheduleProcessQueue(this.$$state);
23949
23950       return result.promise;
23951     },
23952
23953     "catch": function(callback) {
23954       return this.then(null, callback);
23955     },
23956
23957     "finally": function(callback, progressBack) {
23958       return this.then(function(value) {
23959         return handleCallback(value, true, callback);
23960       }, function(error) {
23961         return handleCallback(error, false, callback);
23962       }, progressBack);
23963     }
23964   });
23965
23966   //Faster, more basic than angular.bind http://jsperf.com/angular-bind-vs-custom-vs-native
23967   function simpleBind(context, fn) {
23968     return function(value) {
23969       fn.call(context, value);
23970     };
23971   }
23972
23973   function processQueue(state) {
23974     var fn, deferred, pending;
23975
23976     pending = state.pending;
23977     state.processScheduled = false;
23978     state.pending = undefined;
23979     for (var i = 0, ii = pending.length; i < ii; ++i) {
23980       deferred = pending[i][0];
23981       fn = pending[i][state.status];
23982       try {
23983         if (isFunction(fn)) {
23984           deferred.resolve(fn(state.value));
23985         } else if (state.status === 1) {
23986           deferred.resolve(state.value);
23987         } else {
23988           deferred.reject(state.value);
23989         }
23990       } catch (e) {
23991         deferred.reject(e);
23992         exceptionHandler(e);
23993       }
23994     }
23995   }
23996
23997   function scheduleProcessQueue(state) {
23998     if (state.processScheduled || !state.pending) return;
23999     state.processScheduled = true;
24000     nextTick(function() { processQueue(state); });
24001   }
24002
24003   function Deferred() {
24004     this.promise = new Promise();
24005     //Necessary to support unbound execution :/
24006     this.resolve = simpleBind(this, this.resolve);
24007     this.reject = simpleBind(this, this.reject);
24008     this.notify = simpleBind(this, this.notify);
24009   }
24010
24011   extend(Deferred.prototype, {
24012     resolve: function(val) {
24013       if (this.promise.$$state.status) return;
24014       if (val === this.promise) {
24015         this.$$reject($qMinErr(
24016           'qcycle',
24017           "Expected promise to be resolved with value other than itself '{0}'",
24018           val));
24019       } else {
24020         this.$$resolve(val);
24021       }
24022
24023     },
24024
24025     $$resolve: function(val) {
24026       var then, fns;
24027
24028       fns = callOnce(this, this.$$resolve, this.$$reject);
24029       try {
24030         if ((isObject(val) || isFunction(val))) then = val && val.then;
24031         if (isFunction(then)) {
24032           this.promise.$$state.status = -1;
24033           then.call(val, fns[0], fns[1], this.notify);
24034         } else {
24035           this.promise.$$state.value = val;
24036           this.promise.$$state.status = 1;
24037           scheduleProcessQueue(this.promise.$$state);
24038         }
24039       } catch (e) {
24040         fns[1](e);
24041         exceptionHandler(e);
24042       }
24043     },
24044
24045     reject: function(reason) {
24046       if (this.promise.$$state.status) return;
24047       this.$$reject(reason);
24048     },
24049
24050     $$reject: function(reason) {
24051       this.promise.$$state.value = reason;
24052       this.promise.$$state.status = 2;
24053       scheduleProcessQueue(this.promise.$$state);
24054     },
24055
24056     notify: function(progress) {
24057       var callbacks = this.promise.$$state.pending;
24058
24059       if ((this.promise.$$state.status <= 0) && callbacks && callbacks.length) {
24060         nextTick(function() {
24061           var callback, result;
24062           for (var i = 0, ii = callbacks.length; i < ii; i++) {
24063             result = callbacks[i][0];
24064             callback = callbacks[i][3];
24065             try {
24066               result.notify(isFunction(callback) ? callback(progress) : progress);
24067             } catch (e) {
24068               exceptionHandler(e);
24069             }
24070           }
24071         });
24072       }
24073     }
24074   });
24075
24076   /**
24077    * @ngdoc method
24078    * @name $q#reject
24079    * @kind function
24080    *
24081    * @description
24082    * Creates a promise that is resolved as rejected with the specified `reason`. This api should be
24083    * used to forward rejection in a chain of promises. If you are dealing with the last promise in
24084    * a promise chain, you don't need to worry about it.
24085    *
24086    * When comparing deferreds/promises to the familiar behavior of try/catch/throw, think of
24087    * `reject` as the `throw` keyword in JavaScript. This also means that if you "catch" an error via
24088    * a promise error callback and you want to forward the error to the promise derived from the
24089    * current promise, you have to "rethrow" the error by returning a rejection constructed via
24090    * `reject`.
24091    *
24092    * ```js
24093    *   promiseB = promiseA.then(function(result) {
24094    *     // success: do something and resolve promiseB
24095    *     //          with the old or a new result
24096    *     return result;
24097    *   }, function(reason) {
24098    *     // error: handle the error if possible and
24099    *     //        resolve promiseB with newPromiseOrValue,
24100    *     //        otherwise forward the rejection to promiseB
24101    *     if (canHandle(reason)) {
24102    *      // handle the error and recover
24103    *      return newPromiseOrValue;
24104    *     }
24105    *     return $q.reject(reason);
24106    *   });
24107    * ```
24108    *
24109    * @param {*} reason Constant, message, exception or an object representing the rejection reason.
24110    * @returns {Promise} Returns a promise that was already resolved as rejected with the `reason`.
24111    */
24112   var reject = function(reason) {
24113     var result = new Deferred();
24114     result.reject(reason);
24115     return result.promise;
24116   };
24117
24118   var makePromise = function makePromise(value, resolved) {
24119     var result = new Deferred();
24120     if (resolved) {
24121       result.resolve(value);
24122     } else {
24123       result.reject(value);
24124     }
24125     return result.promise;
24126   };
24127
24128   var handleCallback = function handleCallback(value, isResolved, callback) {
24129     var callbackOutput = null;
24130     try {
24131       if (isFunction(callback)) callbackOutput = callback();
24132     } catch (e) {
24133       return makePromise(e, false);
24134     }
24135     if (isPromiseLike(callbackOutput)) {
24136       return callbackOutput.then(function() {
24137         return makePromise(value, isResolved);
24138       }, function(error) {
24139         return makePromise(error, false);
24140       });
24141     } else {
24142       return makePromise(value, isResolved);
24143     }
24144   };
24145
24146   /**
24147    * @ngdoc method
24148    * @name $q#when
24149    * @kind function
24150    *
24151    * @description
24152    * Wraps an object that might be a value or a (3rd party) then-able promise into a $q promise.
24153    * This is useful when you are dealing with an object that might or might not be a promise, or if
24154    * the promise comes from a source that can't be trusted.
24155    *
24156    * @param {*} value Value or a promise
24157    * @param {Function=} successCallback
24158    * @param {Function=} errorCallback
24159    * @param {Function=} progressCallback
24160    * @returns {Promise} Returns a promise of the passed value or promise
24161    */
24162
24163
24164   var when = function(value, callback, errback, progressBack) {
24165     var result = new Deferred();
24166     result.resolve(value);
24167     return result.promise.then(callback, errback, progressBack);
24168   };
24169
24170   /**
24171    * @ngdoc method
24172    * @name $q#resolve
24173    * @kind function
24174    *
24175    * @description
24176    * Alias of {@link ng.$q#when when} to maintain naming consistency with ES6.
24177    *
24178    * @param {*} value Value or a promise
24179    * @param {Function=} successCallback
24180    * @param {Function=} errorCallback
24181    * @param {Function=} progressCallback
24182    * @returns {Promise} Returns a promise of the passed value or promise
24183    */
24184   var resolve = when;
24185
24186   /**
24187    * @ngdoc method
24188    * @name $q#all
24189    * @kind function
24190    *
24191    * @description
24192    * Combines multiple promises into a single promise that is resolved when all of the input
24193    * promises are resolved.
24194    *
24195    * @param {Array.<Promise>|Object.<Promise>} promises An array or hash of promises.
24196    * @returns {Promise} Returns a single promise that will be resolved with an array/hash of values,
24197    *   each value corresponding to the promise at the same index/key in the `promises` array/hash.
24198    *   If any of the promises is resolved with a rejection, this resulting promise will be rejected
24199    *   with the same rejection value.
24200    */
24201
24202   function all(promises) {
24203     var deferred = new Deferred(),
24204         counter = 0,
24205         results = isArray(promises) ? [] : {};
24206
24207     forEach(promises, function(promise, key) {
24208       counter++;
24209       when(promise).then(function(value) {
24210         if (results.hasOwnProperty(key)) return;
24211         results[key] = value;
24212         if (!(--counter)) deferred.resolve(results);
24213       }, function(reason) {
24214         if (results.hasOwnProperty(key)) return;
24215         deferred.reject(reason);
24216       });
24217     });
24218
24219     if (counter === 0) {
24220       deferred.resolve(results);
24221     }
24222
24223     return deferred.promise;
24224   }
24225
24226   var $Q = function Q(resolver) {
24227     if (!isFunction(resolver)) {
24228       throw $qMinErr('norslvr', "Expected resolverFn, got '{0}'", resolver);
24229     }
24230
24231     if (!(this instanceof Q)) {
24232       // More useful when $Q is the Promise itself.
24233       return new Q(resolver);
24234     }
24235
24236     var deferred = new Deferred();
24237
24238     function resolveFn(value) {
24239       deferred.resolve(value);
24240     }
24241
24242     function rejectFn(reason) {
24243       deferred.reject(reason);
24244     }
24245
24246     resolver(resolveFn, rejectFn);
24247
24248     return deferred.promise;
24249   };
24250
24251   $Q.defer = defer;
24252   $Q.reject = reject;
24253   $Q.when = when;
24254   $Q.resolve = resolve;
24255   $Q.all = all;
24256
24257   return $Q;
24258 }
24259
24260 function $$RAFProvider() { //rAF
24261   this.$get = ['$window', '$timeout', function($window, $timeout) {
24262     var requestAnimationFrame = $window.requestAnimationFrame ||
24263                                 $window.webkitRequestAnimationFrame;
24264
24265     var cancelAnimationFrame = $window.cancelAnimationFrame ||
24266                                $window.webkitCancelAnimationFrame ||
24267                                $window.webkitCancelRequestAnimationFrame;
24268
24269     var rafSupported = !!requestAnimationFrame;
24270     var raf = rafSupported
24271       ? function(fn) {
24272           var id = requestAnimationFrame(fn);
24273           return function() {
24274             cancelAnimationFrame(id);
24275           };
24276         }
24277       : function(fn) {
24278           var timer = $timeout(fn, 16.66, false); // 1000 / 60 = 16.666
24279           return function() {
24280             $timeout.cancel(timer);
24281           };
24282         };
24283
24284     raf.supported = rafSupported;
24285
24286     return raf;
24287   }];
24288 }
24289
24290 /**
24291  * DESIGN NOTES
24292  *
24293  * The design decisions behind the scope are heavily favored for speed and memory consumption.
24294  *
24295  * The typical use of scope is to watch the expressions, which most of the time return the same
24296  * value as last time so we optimize the operation.
24297  *
24298  * Closures construction is expensive in terms of speed as well as memory:
24299  *   - No closures, instead use prototypical inheritance for API
24300  *   - Internal state needs to be stored on scope directly, which means that private state is
24301  *     exposed as $$____ properties
24302  *
24303  * Loop operations are optimized by using while(count--) { ... }
24304  *   - This means that in order to keep the same order of execution as addition we have to add
24305  *     items to the array at the beginning (unshift) instead of at the end (push)
24306  *
24307  * Child scopes are created and removed often
24308  *   - Using an array would be slow since inserts in the middle are expensive; so we use linked lists
24309  *
24310  * There are fewer watches than observers. This is why you don't want the observer to be implemented
24311  * in the same way as watch. Watch requires return of the initialization function which is expensive
24312  * to construct.
24313  */
24314
24315
24316 /**
24317  * @ngdoc provider
24318  * @name $rootScopeProvider
24319  * @description
24320  *
24321  * Provider for the $rootScope service.
24322  */
24323
24324 /**
24325  * @ngdoc method
24326  * @name $rootScopeProvider#digestTtl
24327  * @description
24328  *
24329  * Sets the number of `$digest` iterations the scope should attempt to execute before giving up and
24330  * assuming that the model is unstable.
24331  *
24332  * The current default is 10 iterations.
24333  *
24334  * In complex applications it's possible that the dependencies between `$watch`s will result in
24335  * several digest iterations. However if an application needs more than the default 10 digest
24336  * iterations for its model to stabilize then you should investigate what is causing the model to
24337  * continuously change during the digest.
24338  *
24339  * Increasing the TTL could have performance implications, so you should not change it without
24340  * proper justification.
24341  *
24342  * @param {number} limit The number of digest iterations.
24343  */
24344
24345
24346 /**
24347  * @ngdoc service
24348  * @name $rootScope
24349  * @description
24350  *
24351  * Every application has a single root {@link ng.$rootScope.Scope scope}.
24352  * All other scopes are descendant scopes of the root scope. Scopes provide separation
24353  * between the model and the view, via a mechanism for watching the model for changes.
24354  * They also provide event emission/broadcast and subscription facility. See the
24355  * {@link guide/scope developer guide on scopes}.
24356  */
24357 function $RootScopeProvider() {
24358   var TTL = 10;
24359   var $rootScopeMinErr = minErr('$rootScope');
24360   var lastDirtyWatch = null;
24361   var applyAsyncId = null;
24362
24363   this.digestTtl = function(value) {
24364     if (arguments.length) {
24365       TTL = value;
24366     }
24367     return TTL;
24368   };
24369
24370   function createChildScopeClass(parent) {
24371     function ChildScope() {
24372       this.$$watchers = this.$$nextSibling =
24373           this.$$childHead = this.$$childTail = null;
24374       this.$$listeners = {};
24375       this.$$listenerCount = {};
24376       this.$$watchersCount = 0;
24377       this.$id = nextUid();
24378       this.$$ChildScope = null;
24379     }
24380     ChildScope.prototype = parent;
24381     return ChildScope;
24382   }
24383
24384   this.$get = ['$injector', '$exceptionHandler', '$parse', '$browser',
24385       function($injector, $exceptionHandler, $parse, $browser) {
24386
24387     function destroyChildScope($event) {
24388         $event.currentScope.$$destroyed = true;
24389     }
24390
24391     function cleanUpScope($scope) {
24392
24393       if (msie === 9) {
24394         // There is a memory leak in IE9 if all child scopes are not disconnected
24395         // completely when a scope is destroyed. So this code will recurse up through
24396         // all this scopes children
24397         //
24398         // See issue https://github.com/angular/angular.js/issues/10706
24399         $scope.$$childHead && cleanUpScope($scope.$$childHead);
24400         $scope.$$nextSibling && cleanUpScope($scope.$$nextSibling);
24401       }
24402
24403       // The code below works around IE9 and V8's memory leaks
24404       //
24405       // See:
24406       // - https://code.google.com/p/v8/issues/detail?id=2073#c26
24407       // - https://github.com/angular/angular.js/issues/6794#issuecomment-38648909
24408       // - https://github.com/angular/angular.js/issues/1313#issuecomment-10378451
24409
24410       $scope.$parent = $scope.$$nextSibling = $scope.$$prevSibling = $scope.$$childHead =
24411           $scope.$$childTail = $scope.$root = $scope.$$watchers = null;
24412     }
24413
24414     /**
24415      * @ngdoc type
24416      * @name $rootScope.Scope
24417      *
24418      * @description
24419      * A root scope can be retrieved using the {@link ng.$rootScope $rootScope} key from the
24420      * {@link auto.$injector $injector}. Child scopes are created using the
24421      * {@link ng.$rootScope.Scope#$new $new()} method. (Most scopes are created automatically when
24422      * compiled HTML template is executed.) See also the {@link guide/scope Scopes guide} for
24423      * an in-depth introduction and usage examples.
24424      *
24425      *
24426      * # Inheritance
24427      * A scope can inherit from a parent scope, as in this example:
24428      * ```js
24429          var parent = $rootScope;
24430          var child = parent.$new();
24431
24432          parent.salutation = "Hello";
24433          expect(child.salutation).toEqual('Hello');
24434
24435          child.salutation = "Welcome";
24436          expect(child.salutation).toEqual('Welcome');
24437          expect(parent.salutation).toEqual('Hello');
24438      * ```
24439      *
24440      * When interacting with `Scope` in tests, additional helper methods are available on the
24441      * instances of `Scope` type. See {@link ngMock.$rootScope.Scope ngMock Scope} for additional
24442      * details.
24443      *
24444      *
24445      * @param {Object.<string, function()>=} providers Map of service factory which need to be
24446      *                                       provided for the current scope. Defaults to {@link ng}.
24447      * @param {Object.<string, *>=} instanceCache Provides pre-instantiated services which should
24448      *                              append/override services provided by `providers`. This is handy
24449      *                              when unit-testing and having the need to override a default
24450      *                              service.
24451      * @returns {Object} Newly created scope.
24452      *
24453      */
24454     function Scope() {
24455       this.$id = nextUid();
24456       this.$$phase = this.$parent = this.$$watchers =
24457                      this.$$nextSibling = this.$$prevSibling =
24458                      this.$$childHead = this.$$childTail = null;
24459       this.$root = this;
24460       this.$$destroyed = false;
24461       this.$$listeners = {};
24462       this.$$listenerCount = {};
24463       this.$$watchersCount = 0;
24464       this.$$isolateBindings = null;
24465     }
24466
24467     /**
24468      * @ngdoc property
24469      * @name $rootScope.Scope#$id
24470      *
24471      * @description
24472      * Unique scope ID (monotonically increasing) useful for debugging.
24473      */
24474
24475      /**
24476       * @ngdoc property
24477       * @name $rootScope.Scope#$parent
24478       *
24479       * @description
24480       * Reference to the parent scope.
24481       */
24482
24483       /**
24484        * @ngdoc property
24485        * @name $rootScope.Scope#$root
24486        *
24487        * @description
24488        * Reference to the root scope.
24489        */
24490
24491     Scope.prototype = {
24492       constructor: Scope,
24493       /**
24494        * @ngdoc method
24495        * @name $rootScope.Scope#$new
24496        * @kind function
24497        *
24498        * @description
24499        * Creates a new child {@link ng.$rootScope.Scope scope}.
24500        *
24501        * The parent scope will propagate the {@link ng.$rootScope.Scope#$digest $digest()} event.
24502        * The scope can be removed from the scope hierarchy using {@link ng.$rootScope.Scope#$destroy $destroy()}.
24503        *
24504        * {@link ng.$rootScope.Scope#$destroy $destroy()} must be called on a scope when it is
24505        * desired for the scope and its child scopes to be permanently detached from the parent and
24506        * thus stop participating in model change detection and listener notification by invoking.
24507        *
24508        * @param {boolean} isolate If true, then the scope does not prototypically inherit from the
24509        *         parent scope. The scope is isolated, as it can not see parent scope properties.
24510        *         When creating widgets, it is useful for the widget to not accidentally read parent
24511        *         state.
24512        *
24513        * @param {Scope} [parent=this] The {@link ng.$rootScope.Scope `Scope`} that will be the `$parent`
24514        *                              of the newly created scope. Defaults to `this` scope if not provided.
24515        *                              This is used when creating a transclude scope to correctly place it
24516        *                              in the scope hierarchy while maintaining the correct prototypical
24517        *                              inheritance.
24518        *
24519        * @returns {Object} The newly created child scope.
24520        *
24521        */
24522       $new: function(isolate, parent) {
24523         var child;
24524
24525         parent = parent || this;
24526
24527         if (isolate) {
24528           child = new Scope();
24529           child.$root = this.$root;
24530         } else {
24531           // Only create a child scope class if somebody asks for one,
24532           // but cache it to allow the VM to optimize lookups.
24533           if (!this.$$ChildScope) {
24534             this.$$ChildScope = createChildScopeClass(this);
24535           }
24536           child = new this.$$ChildScope();
24537         }
24538         child.$parent = parent;
24539         child.$$prevSibling = parent.$$childTail;
24540         if (parent.$$childHead) {
24541           parent.$$childTail.$$nextSibling = child;
24542           parent.$$childTail = child;
24543         } else {
24544           parent.$$childHead = parent.$$childTail = child;
24545         }
24546
24547         // When the new scope is not isolated or we inherit from `this`, and
24548         // the parent scope is destroyed, the property `$$destroyed` is inherited
24549         // prototypically. In all other cases, this property needs to be set
24550         // when the parent scope is destroyed.
24551         // The listener needs to be added after the parent is set
24552         if (isolate || parent != this) child.$on('$destroy', destroyChildScope);
24553
24554         return child;
24555       },
24556
24557       /**
24558        * @ngdoc method
24559        * @name $rootScope.Scope#$watch
24560        * @kind function
24561        *
24562        * @description
24563        * Registers a `listener` callback to be executed whenever the `watchExpression` changes.
24564        *
24565        * - The `watchExpression` is called on every call to {@link ng.$rootScope.Scope#$digest
24566        *   $digest()} and should return the value that will be watched. (`watchExpression` should not change
24567        *   its value when executed multiple times with the same input because it may be executed multiple
24568        *   times by {@link ng.$rootScope.Scope#$digest $digest()}. That is, `watchExpression` should be
24569        *   [idempotent](http://en.wikipedia.org/wiki/Idempotence).
24570        * - The `listener` is called only when the value from the current `watchExpression` and the
24571        *   previous call to `watchExpression` are not equal (with the exception of the initial run,
24572        *   see below). Inequality is determined according to reference inequality,
24573        *   [strict comparison](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Comparison_Operators)
24574        *    via the `!==` Javascript operator, unless `objectEquality == true`
24575        *   (see next point)
24576        * - When `objectEquality == true`, inequality of the `watchExpression` is determined
24577        *   according to the {@link angular.equals} function. To save the value of the object for
24578        *   later comparison, the {@link angular.copy} function is used. This therefore means that
24579        *   watching complex objects will have adverse memory and performance implications.
24580        * - The watch `listener` may change the model, which may trigger other `listener`s to fire.
24581        *   This is achieved by rerunning the watchers until no changes are detected. The rerun
24582        *   iteration limit is 10 to prevent an infinite loop deadlock.
24583        *
24584        *
24585        * If you want to be notified whenever {@link ng.$rootScope.Scope#$digest $digest} is called,
24586        * you can register a `watchExpression` function with no `listener`. (Be prepared for
24587        * multiple calls to your `watchExpression` because it will execute multiple times in a
24588        * single {@link ng.$rootScope.Scope#$digest $digest} cycle if a change is detected.)
24589        *
24590        * After a watcher is registered with the scope, the `listener` fn is called asynchronously
24591        * (via {@link ng.$rootScope.Scope#$evalAsync $evalAsync}) to initialize the
24592        * watcher. In rare cases, this is undesirable because the listener is called when the result
24593        * of `watchExpression` didn't change. To detect this scenario within the `listener` fn, you
24594        * can compare the `newVal` and `oldVal`. If these two values are identical (`===`) then the
24595        * listener was called due to initialization.
24596        *
24597        *
24598        *
24599        * # Example
24600        * ```js
24601            // let's assume that scope was dependency injected as the $rootScope
24602            var scope = $rootScope;
24603            scope.name = 'misko';
24604            scope.counter = 0;
24605
24606            expect(scope.counter).toEqual(0);
24607            scope.$watch('name', function(newValue, oldValue) {
24608              scope.counter = scope.counter + 1;
24609            });
24610            expect(scope.counter).toEqual(0);
24611
24612            scope.$digest();
24613            // the listener is always called during the first $digest loop after it was registered
24614            expect(scope.counter).toEqual(1);
24615
24616            scope.$digest();
24617            // but now it will not be called unless the value changes
24618            expect(scope.counter).toEqual(1);
24619
24620            scope.name = 'adam';
24621            scope.$digest();
24622            expect(scope.counter).toEqual(2);
24623
24624
24625
24626            // Using a function as a watchExpression
24627            var food;
24628            scope.foodCounter = 0;
24629            expect(scope.foodCounter).toEqual(0);
24630            scope.$watch(
24631              // This function returns the value being watched. It is called for each turn of the $digest loop
24632              function() { return food; },
24633              // This is the change listener, called when the value returned from the above function changes
24634              function(newValue, oldValue) {
24635                if ( newValue !== oldValue ) {
24636                  // Only increment the counter if the value changed
24637                  scope.foodCounter = scope.foodCounter + 1;
24638                }
24639              }
24640            );
24641            // No digest has been run so the counter will be zero
24642            expect(scope.foodCounter).toEqual(0);
24643
24644            // Run the digest but since food has not changed count will still be zero
24645            scope.$digest();
24646            expect(scope.foodCounter).toEqual(0);
24647
24648            // Update food and run digest.  Now the counter will increment
24649            food = 'cheeseburger';
24650            scope.$digest();
24651            expect(scope.foodCounter).toEqual(1);
24652
24653        * ```
24654        *
24655        *
24656        *
24657        * @param {(function()|string)} watchExpression Expression that is evaluated on each
24658        *    {@link ng.$rootScope.Scope#$digest $digest} cycle. A change in the return value triggers
24659        *    a call to the `listener`.
24660        *
24661        *    - `string`: Evaluated as {@link guide/expression expression}
24662        *    - `function(scope)`: called with current `scope` as a parameter.
24663        * @param {function(newVal, oldVal, scope)} listener Callback called whenever the value
24664        *    of `watchExpression` changes.
24665        *
24666        *    - `newVal` contains the current value of the `watchExpression`
24667        *    - `oldVal` contains the previous value of the `watchExpression`
24668        *    - `scope` refers to the current scope
24669        * @param {boolean=} objectEquality Compare for object equality using {@link angular.equals} instead of
24670        *     comparing for reference equality.
24671        * @returns {function()} Returns a deregistration function for this listener.
24672        */
24673       $watch: function(watchExp, listener, objectEquality, prettyPrintExpression) {
24674         var get = $parse(watchExp);
24675
24676         if (get.$$watchDelegate) {
24677           return get.$$watchDelegate(this, listener, objectEquality, get, watchExp);
24678         }
24679         var scope = this,
24680             array = scope.$$watchers,
24681             watcher = {
24682               fn: listener,
24683               last: initWatchVal,
24684               get: get,
24685               exp: prettyPrintExpression || watchExp,
24686               eq: !!objectEquality
24687             };
24688
24689         lastDirtyWatch = null;
24690
24691         if (!isFunction(listener)) {
24692           watcher.fn = noop;
24693         }
24694
24695         if (!array) {
24696           array = scope.$$watchers = [];
24697         }
24698         // we use unshift since we use a while loop in $digest for speed.
24699         // the while loop reads in reverse order.
24700         array.unshift(watcher);
24701         incrementWatchersCount(this, 1);
24702
24703         return function deregisterWatch() {
24704           if (arrayRemove(array, watcher) >= 0) {
24705             incrementWatchersCount(scope, -1);
24706           }
24707           lastDirtyWatch = null;
24708         };
24709       },
24710
24711       /**
24712        * @ngdoc method
24713        * @name $rootScope.Scope#$watchGroup
24714        * @kind function
24715        *
24716        * @description
24717        * A variant of {@link ng.$rootScope.Scope#$watch $watch()} where it watches an array of `watchExpressions`.
24718        * If any one expression in the collection changes the `listener` is executed.
24719        *
24720        * - The items in the `watchExpressions` array are observed via standard $watch operation and are examined on every
24721        *   call to $digest() to see if any items changes.
24722        * - The `listener` is called whenever any expression in the `watchExpressions` array changes.
24723        *
24724        * @param {Array.<string|Function(scope)>} watchExpressions Array of expressions that will be individually
24725        * watched using {@link ng.$rootScope.Scope#$watch $watch()}
24726        *
24727        * @param {function(newValues, oldValues, scope)} listener Callback called whenever the return value of any
24728        *    expression in `watchExpressions` changes
24729        *    The `newValues` array contains the current values of the `watchExpressions`, with the indexes matching
24730        *    those of `watchExpression`
24731        *    and the `oldValues` array contains the previous values of the `watchExpressions`, with the indexes matching
24732        *    those of `watchExpression`
24733        *    The `scope` refers to the current scope.
24734        * @returns {function()} Returns a de-registration function for all listeners.
24735        */
24736       $watchGroup: function(watchExpressions, listener) {
24737         var oldValues = new Array(watchExpressions.length);
24738         var newValues = new Array(watchExpressions.length);
24739         var deregisterFns = [];
24740         var self = this;
24741         var changeReactionScheduled = false;
24742         var firstRun = true;
24743
24744         if (!watchExpressions.length) {
24745           // No expressions means we call the listener ASAP
24746           var shouldCall = true;
24747           self.$evalAsync(function() {
24748             if (shouldCall) listener(newValues, newValues, self);
24749           });
24750           return function deregisterWatchGroup() {
24751             shouldCall = false;
24752           };
24753         }
24754
24755         if (watchExpressions.length === 1) {
24756           // Special case size of one
24757           return this.$watch(watchExpressions[0], function watchGroupAction(value, oldValue, scope) {
24758             newValues[0] = value;
24759             oldValues[0] = oldValue;
24760             listener(newValues, (value === oldValue) ? newValues : oldValues, scope);
24761           });
24762         }
24763
24764         forEach(watchExpressions, function(expr, i) {
24765           var unwatchFn = self.$watch(expr, function watchGroupSubAction(value, oldValue) {
24766             newValues[i] = value;
24767             oldValues[i] = oldValue;
24768             if (!changeReactionScheduled) {
24769               changeReactionScheduled = true;
24770               self.$evalAsync(watchGroupAction);
24771             }
24772           });
24773           deregisterFns.push(unwatchFn);
24774         });
24775
24776         function watchGroupAction() {
24777           changeReactionScheduled = false;
24778
24779           if (firstRun) {
24780             firstRun = false;
24781             listener(newValues, newValues, self);
24782           } else {
24783             listener(newValues, oldValues, self);
24784           }
24785         }
24786
24787         return function deregisterWatchGroup() {
24788           while (deregisterFns.length) {
24789             deregisterFns.shift()();
24790           }
24791         };
24792       },
24793
24794
24795       /**
24796        * @ngdoc method
24797        * @name $rootScope.Scope#$watchCollection
24798        * @kind function
24799        *
24800        * @description
24801        * Shallow watches the properties of an object and fires whenever any of the properties change
24802        * (for arrays, this implies watching the array items; for object maps, this implies watching
24803        * the properties). If a change is detected, the `listener` callback is fired.
24804        *
24805        * - The `obj` collection is observed via standard $watch operation and is examined on every
24806        *   call to $digest() to see if any items have been added, removed, or moved.
24807        * - The `listener` is called whenever anything within the `obj` has changed. Examples include
24808        *   adding, removing, and moving items belonging to an object or array.
24809        *
24810        *
24811        * # Example
24812        * ```js
24813           $scope.names = ['igor', 'matias', 'misko', 'james'];
24814           $scope.dataCount = 4;
24815
24816           $scope.$watchCollection('names', function(newNames, oldNames) {
24817             $scope.dataCount = newNames.length;
24818           });
24819
24820           expect($scope.dataCount).toEqual(4);
24821           $scope.$digest();
24822
24823           //still at 4 ... no changes
24824           expect($scope.dataCount).toEqual(4);
24825
24826           $scope.names.pop();
24827           $scope.$digest();
24828
24829           //now there's been a change
24830           expect($scope.dataCount).toEqual(3);
24831        * ```
24832        *
24833        *
24834        * @param {string|function(scope)} obj Evaluated as {@link guide/expression expression}. The
24835        *    expression value should evaluate to an object or an array which is observed on each
24836        *    {@link ng.$rootScope.Scope#$digest $digest} cycle. Any shallow change within the
24837        *    collection will trigger a call to the `listener`.
24838        *
24839        * @param {function(newCollection, oldCollection, scope)} listener a callback function called
24840        *    when a change is detected.
24841        *    - The `newCollection` object is the newly modified data obtained from the `obj` expression
24842        *    - The `oldCollection` object is a copy of the former collection data.
24843        *      Due to performance considerations, the`oldCollection` value is computed only if the
24844        *      `listener` function declares two or more arguments.
24845        *    - The `scope` argument refers to the current scope.
24846        *
24847        * @returns {function()} Returns a de-registration function for this listener. When the
24848        *    de-registration function is executed, the internal watch operation is terminated.
24849        */
24850       $watchCollection: function(obj, listener) {
24851         $watchCollectionInterceptor.$stateful = true;
24852
24853         var self = this;
24854         // the current value, updated on each dirty-check run
24855         var newValue;
24856         // a shallow copy of the newValue from the last dirty-check run,
24857         // updated to match newValue during dirty-check run
24858         var oldValue;
24859         // a shallow copy of the newValue from when the last change happened
24860         var veryOldValue;
24861         // only track veryOldValue if the listener is asking for it
24862         var trackVeryOldValue = (listener.length > 1);
24863         var changeDetected = 0;
24864         var changeDetector = $parse(obj, $watchCollectionInterceptor);
24865         var internalArray = [];
24866         var internalObject = {};
24867         var initRun = true;
24868         var oldLength = 0;
24869
24870         function $watchCollectionInterceptor(_value) {
24871           newValue = _value;
24872           var newLength, key, bothNaN, newItem, oldItem;
24873
24874           // If the new value is undefined, then return undefined as the watch may be a one-time watch
24875           if (isUndefined(newValue)) return;
24876
24877           if (!isObject(newValue)) { // if primitive
24878             if (oldValue !== newValue) {
24879               oldValue = newValue;
24880               changeDetected++;
24881             }
24882           } else if (isArrayLike(newValue)) {
24883             if (oldValue !== internalArray) {
24884               // we are transitioning from something which was not an array into array.
24885               oldValue = internalArray;
24886               oldLength = oldValue.length = 0;
24887               changeDetected++;
24888             }
24889
24890             newLength = newValue.length;
24891
24892             if (oldLength !== newLength) {
24893               // if lengths do not match we need to trigger change notification
24894               changeDetected++;
24895               oldValue.length = oldLength = newLength;
24896             }
24897             // copy the items to oldValue and look for changes.
24898             for (var i = 0; i < newLength; i++) {
24899               oldItem = oldValue[i];
24900               newItem = newValue[i];
24901
24902               bothNaN = (oldItem !== oldItem) && (newItem !== newItem);
24903               if (!bothNaN && (oldItem !== newItem)) {
24904                 changeDetected++;
24905                 oldValue[i] = newItem;
24906               }
24907             }
24908           } else {
24909             if (oldValue !== internalObject) {
24910               // we are transitioning from something which was not an object into object.
24911               oldValue = internalObject = {};
24912               oldLength = 0;
24913               changeDetected++;
24914             }
24915             // copy the items to oldValue and look for changes.
24916             newLength = 0;
24917             for (key in newValue) {
24918               if (hasOwnProperty.call(newValue, key)) {
24919                 newLength++;
24920                 newItem = newValue[key];
24921                 oldItem = oldValue[key];
24922
24923                 if (key in oldValue) {
24924                   bothNaN = (oldItem !== oldItem) && (newItem !== newItem);
24925                   if (!bothNaN && (oldItem !== newItem)) {
24926                     changeDetected++;
24927                     oldValue[key] = newItem;
24928                   }
24929                 } else {
24930                   oldLength++;
24931                   oldValue[key] = newItem;
24932                   changeDetected++;
24933                 }
24934               }
24935             }
24936             if (oldLength > newLength) {
24937               // we used to have more keys, need to find them and destroy them.
24938               changeDetected++;
24939               for (key in oldValue) {
24940                 if (!hasOwnProperty.call(newValue, key)) {
24941                   oldLength--;
24942                   delete oldValue[key];
24943                 }
24944               }
24945             }
24946           }
24947           return changeDetected;
24948         }
24949
24950         function $watchCollectionAction() {
24951           if (initRun) {
24952             initRun = false;
24953             listener(newValue, newValue, self);
24954           } else {
24955             listener(newValue, veryOldValue, self);
24956           }
24957
24958           // make a copy for the next time a collection is changed
24959           if (trackVeryOldValue) {
24960             if (!isObject(newValue)) {
24961               //primitive
24962               veryOldValue = newValue;
24963             } else if (isArrayLike(newValue)) {
24964               veryOldValue = new Array(newValue.length);
24965               for (var i = 0; i < newValue.length; i++) {
24966                 veryOldValue[i] = newValue[i];
24967               }
24968             } else { // if object
24969               veryOldValue = {};
24970               for (var key in newValue) {
24971                 if (hasOwnProperty.call(newValue, key)) {
24972                   veryOldValue[key] = newValue[key];
24973                 }
24974               }
24975             }
24976           }
24977         }
24978
24979         return this.$watch(changeDetector, $watchCollectionAction);
24980       },
24981
24982       /**
24983        * @ngdoc method
24984        * @name $rootScope.Scope#$digest
24985        * @kind function
24986        *
24987        * @description
24988        * Processes all of the {@link ng.$rootScope.Scope#$watch watchers} of the current scope and
24989        * its children. Because a {@link ng.$rootScope.Scope#$watch watcher}'s listener can change
24990        * the model, the `$digest()` keeps calling the {@link ng.$rootScope.Scope#$watch watchers}
24991        * until no more listeners are firing. This means that it is possible to get into an infinite
24992        * loop. This function will throw `'Maximum iteration limit exceeded.'` if the number of
24993        * iterations exceeds 10.
24994        *
24995        * Usually, you don't call `$digest()` directly in
24996        * {@link ng.directive:ngController controllers} or in
24997        * {@link ng.$compileProvider#directive directives}.
24998        * Instead, you should call {@link ng.$rootScope.Scope#$apply $apply()} (typically from within
24999        * a {@link ng.$compileProvider#directive directive}), which will force a `$digest()`.
25000        *
25001        * If you want to be notified whenever `$digest()` is called,
25002        * you can register a `watchExpression` function with
25003        * {@link ng.$rootScope.Scope#$watch $watch()} with no `listener`.
25004        *
25005        * In unit tests, you may need to call `$digest()` to simulate the scope life cycle.
25006        *
25007        * # Example
25008        * ```js
25009            var scope = ...;
25010            scope.name = 'misko';
25011            scope.counter = 0;
25012
25013            expect(scope.counter).toEqual(0);
25014            scope.$watch('name', function(newValue, oldValue) {
25015              scope.counter = scope.counter + 1;
25016            });
25017            expect(scope.counter).toEqual(0);
25018
25019            scope.$digest();
25020            // the listener is always called during the first $digest loop after it was registered
25021            expect(scope.counter).toEqual(1);
25022
25023            scope.$digest();
25024            // but now it will not be called unless the value changes
25025            expect(scope.counter).toEqual(1);
25026
25027            scope.name = 'adam';
25028            scope.$digest();
25029            expect(scope.counter).toEqual(2);
25030        * ```
25031        *
25032        */
25033       $digest: function() {
25034         var watch, value, last,
25035             watchers,
25036             length,
25037             dirty, ttl = TTL,
25038             next, current, target = this,
25039             watchLog = [],
25040             logIdx, logMsg, asyncTask;
25041
25042         beginPhase('$digest');
25043         // Check for changes to browser url that happened in sync before the call to $digest
25044         $browser.$$checkUrlChange();
25045
25046         if (this === $rootScope && applyAsyncId !== null) {
25047           // If this is the root scope, and $applyAsync has scheduled a deferred $apply(), then
25048           // cancel the scheduled $apply and flush the queue of expressions to be evaluated.
25049           $browser.defer.cancel(applyAsyncId);
25050           flushApplyAsync();
25051         }
25052
25053         lastDirtyWatch = null;
25054
25055         do { // "while dirty" loop
25056           dirty = false;
25057           current = target;
25058
25059           while (asyncQueue.length) {
25060             try {
25061               asyncTask = asyncQueue.shift();
25062               asyncTask.scope.$eval(asyncTask.expression, asyncTask.locals);
25063             } catch (e) {
25064               $exceptionHandler(e);
25065             }
25066             lastDirtyWatch = null;
25067           }
25068
25069           traverseScopesLoop:
25070           do { // "traverse the scopes" loop
25071             if ((watchers = current.$$watchers)) {
25072               // process our watches
25073               length = watchers.length;
25074               while (length--) {
25075                 try {
25076                   watch = watchers[length];
25077                   // Most common watches are on primitives, in which case we can short
25078                   // circuit it with === operator, only when === fails do we use .equals
25079                   if (watch) {
25080                     if ((value = watch.get(current)) !== (last = watch.last) &&
25081                         !(watch.eq
25082                             ? equals(value, last)
25083                             : (typeof value === 'number' && typeof last === 'number'
25084                                && isNaN(value) && isNaN(last)))) {
25085                       dirty = true;
25086                       lastDirtyWatch = watch;
25087                       watch.last = watch.eq ? copy(value, null) : value;
25088                       watch.fn(value, ((last === initWatchVal) ? value : last), current);
25089                       if (ttl < 5) {
25090                         logIdx = 4 - ttl;
25091                         if (!watchLog[logIdx]) watchLog[logIdx] = [];
25092                         watchLog[logIdx].push({
25093                           msg: isFunction(watch.exp) ? 'fn: ' + (watch.exp.name || watch.exp.toString()) : watch.exp,
25094                           newVal: value,
25095                           oldVal: last
25096                         });
25097                       }
25098                     } else if (watch === lastDirtyWatch) {
25099                       // If the most recently dirty watcher is now clean, short circuit since the remaining watchers
25100                       // have already been tested.
25101                       dirty = false;
25102                       break traverseScopesLoop;
25103                     }
25104                   }
25105                 } catch (e) {
25106                   $exceptionHandler(e);
25107                 }
25108               }
25109             }
25110
25111             // Insanity Warning: scope depth-first traversal
25112             // yes, this code is a bit crazy, but it works and we have tests to prove it!
25113             // this piece should be kept in sync with the traversal in $broadcast
25114             if (!(next = ((current.$$watchersCount && current.$$childHead) ||
25115                 (current !== target && current.$$nextSibling)))) {
25116               while (current !== target && !(next = current.$$nextSibling)) {
25117                 current = current.$parent;
25118               }
25119             }
25120           } while ((current = next));
25121
25122           // `break traverseScopesLoop;` takes us to here
25123
25124           if ((dirty || asyncQueue.length) && !(ttl--)) {
25125             clearPhase();
25126             throw $rootScopeMinErr('infdig',
25127                 '{0} $digest() iterations reached. Aborting!\n' +
25128                 'Watchers fired in the last 5 iterations: {1}',
25129                 TTL, watchLog);
25130           }
25131
25132         } while (dirty || asyncQueue.length);
25133
25134         clearPhase();
25135
25136         while (postDigestQueue.length) {
25137           try {
25138             postDigestQueue.shift()();
25139           } catch (e) {
25140             $exceptionHandler(e);
25141           }
25142         }
25143       },
25144
25145
25146       /**
25147        * @ngdoc event
25148        * @name $rootScope.Scope#$destroy
25149        * @eventType broadcast on scope being destroyed
25150        *
25151        * @description
25152        * Broadcasted when a scope and its children are being destroyed.
25153        *
25154        * Note that, in AngularJS, there is also a `$destroy` jQuery event, which can be used to
25155        * clean up DOM bindings before an element is removed from the DOM.
25156        */
25157
25158       /**
25159        * @ngdoc method
25160        * @name $rootScope.Scope#$destroy
25161        * @kind function
25162        *
25163        * @description
25164        * Removes the current scope (and all of its children) from the parent scope. Removal implies
25165        * that calls to {@link ng.$rootScope.Scope#$digest $digest()} will no longer
25166        * propagate to the current scope and its children. Removal also implies that the current
25167        * scope is eligible for garbage collection.
25168        *
25169        * The `$destroy()` is usually used by directives such as
25170        * {@link ng.directive:ngRepeat ngRepeat} for managing the
25171        * unrolling of the loop.
25172        *
25173        * Just before a scope is destroyed, a `$destroy` event is broadcasted on this scope.
25174        * Application code can register a `$destroy` event handler that will give it a chance to
25175        * perform any necessary cleanup.
25176        *
25177        * Note that, in AngularJS, there is also a `$destroy` jQuery event, which can be used to
25178        * clean up DOM bindings before an element is removed from the DOM.
25179        */
25180       $destroy: function() {
25181         // We can't destroy a scope that has been already destroyed.
25182         if (this.$$destroyed) return;
25183         var parent = this.$parent;
25184
25185         this.$broadcast('$destroy');
25186         this.$$destroyed = true;
25187
25188         if (this === $rootScope) {
25189           //Remove handlers attached to window when $rootScope is removed
25190           $browser.$$applicationDestroyed();
25191         }
25192
25193         incrementWatchersCount(this, -this.$$watchersCount);
25194         for (var eventName in this.$$listenerCount) {
25195           decrementListenerCount(this, this.$$listenerCount[eventName], eventName);
25196         }
25197
25198         // sever all the references to parent scopes (after this cleanup, the current scope should
25199         // not be retained by any of our references and should be eligible for garbage collection)
25200         if (parent && parent.$$childHead == this) parent.$$childHead = this.$$nextSibling;
25201         if (parent && parent.$$childTail == this) parent.$$childTail = this.$$prevSibling;
25202         if (this.$$prevSibling) this.$$prevSibling.$$nextSibling = this.$$nextSibling;
25203         if (this.$$nextSibling) this.$$nextSibling.$$prevSibling = this.$$prevSibling;
25204
25205         // Disable listeners, watchers and apply/digest methods
25206         this.$destroy = this.$digest = this.$apply = this.$evalAsync = this.$applyAsync = noop;
25207         this.$on = this.$watch = this.$watchGroup = function() { return noop; };
25208         this.$$listeners = {};
25209
25210         // Disconnect the next sibling to prevent `cleanUpScope` destroying those too
25211         this.$$nextSibling = null;
25212         cleanUpScope(this);
25213       },
25214
25215       /**
25216        * @ngdoc method
25217        * @name $rootScope.Scope#$eval
25218        * @kind function
25219        *
25220        * @description
25221        * Executes the `expression` on the current scope and returns the result. Any exceptions in
25222        * the expression are propagated (uncaught). This is useful when evaluating Angular
25223        * expressions.
25224        *
25225        * # Example
25226        * ```js
25227            var scope = ng.$rootScope.Scope();
25228            scope.a = 1;
25229            scope.b = 2;
25230
25231            expect(scope.$eval('a+b')).toEqual(3);
25232            expect(scope.$eval(function(scope){ return scope.a + scope.b; })).toEqual(3);
25233        * ```
25234        *
25235        * @param {(string|function())=} expression An angular expression to be executed.
25236        *
25237        *    - `string`: execute using the rules as defined in  {@link guide/expression expression}.
25238        *    - `function(scope)`: execute the function with the current `scope` parameter.
25239        *
25240        * @param {(object)=} locals Local variables object, useful for overriding values in scope.
25241        * @returns {*} The result of evaluating the expression.
25242        */
25243       $eval: function(expr, locals) {
25244         return $parse(expr)(this, locals);
25245       },
25246
25247       /**
25248        * @ngdoc method
25249        * @name $rootScope.Scope#$evalAsync
25250        * @kind function
25251        *
25252        * @description
25253        * Executes the expression on the current scope at a later point in time.
25254        *
25255        * The `$evalAsync` makes no guarantees as to when the `expression` will be executed, only
25256        * that:
25257        *
25258        *   - it will execute after the function that scheduled the evaluation (preferably before DOM
25259        *     rendering).
25260        *   - at least one {@link ng.$rootScope.Scope#$digest $digest cycle} will be performed after
25261        *     `expression` execution.
25262        *
25263        * Any exceptions from the execution of the expression are forwarded to the
25264        * {@link ng.$exceptionHandler $exceptionHandler} service.
25265        *
25266        * __Note:__ if this function is called outside of a `$digest` cycle, a new `$digest` cycle
25267        * will be scheduled. However, it is encouraged to always call code that changes the model
25268        * from within an `$apply` call. That includes code evaluated via `$evalAsync`.
25269        *
25270        * @param {(string|function())=} expression An angular expression to be executed.
25271        *
25272        *    - `string`: execute using the rules as defined in {@link guide/expression expression}.
25273        *    - `function(scope)`: execute the function with the current `scope` parameter.
25274        *
25275        * @param {(object)=} locals Local variables object, useful for overriding values in scope.
25276        */
25277       $evalAsync: function(expr, locals) {
25278         // if we are outside of an $digest loop and this is the first time we are scheduling async
25279         // task also schedule async auto-flush
25280         if (!$rootScope.$$phase && !asyncQueue.length) {
25281           $browser.defer(function() {
25282             if (asyncQueue.length) {
25283               $rootScope.$digest();
25284             }
25285           });
25286         }
25287
25288         asyncQueue.push({scope: this, expression: expr, locals: locals});
25289       },
25290
25291       $$postDigest: function(fn) {
25292         postDigestQueue.push(fn);
25293       },
25294
25295       /**
25296        * @ngdoc method
25297        * @name $rootScope.Scope#$apply
25298        * @kind function
25299        *
25300        * @description
25301        * `$apply()` is used to execute an expression in angular from outside of the angular
25302        * framework. (For example from browser DOM events, setTimeout, XHR or third party libraries).
25303        * Because we are calling into the angular framework we need to perform proper scope life
25304        * cycle of {@link ng.$exceptionHandler exception handling},
25305        * {@link ng.$rootScope.Scope#$digest executing watches}.
25306        *
25307        * ## Life cycle
25308        *
25309        * # Pseudo-Code of `$apply()`
25310        * ```js
25311            function $apply(expr) {
25312              try {
25313                return $eval(expr);
25314              } catch (e) {
25315                $exceptionHandler(e);
25316              } finally {
25317                $root.$digest();
25318              }
25319            }
25320        * ```
25321        *
25322        *
25323        * Scope's `$apply()` method transitions through the following stages:
25324        *
25325        * 1. The {@link guide/expression expression} is executed using the
25326        *    {@link ng.$rootScope.Scope#$eval $eval()} method.
25327        * 2. Any exceptions from the execution of the expression are forwarded to the
25328        *    {@link ng.$exceptionHandler $exceptionHandler} service.
25329        * 3. The {@link ng.$rootScope.Scope#$watch watch} listeners are fired immediately after the
25330        *    expression was executed using the {@link ng.$rootScope.Scope#$digest $digest()} method.
25331        *
25332        *
25333        * @param {(string|function())=} exp An angular expression to be executed.
25334        *
25335        *    - `string`: execute using the rules as defined in {@link guide/expression expression}.
25336        *    - `function(scope)`: execute the function with current `scope` parameter.
25337        *
25338        * @returns {*} The result of evaluating the expression.
25339        */
25340       $apply: function(expr) {
25341         try {
25342           beginPhase('$apply');
25343           try {
25344             return this.$eval(expr);
25345           } finally {
25346             clearPhase();
25347           }
25348         } catch (e) {
25349           $exceptionHandler(e);
25350         } finally {
25351           try {
25352             $rootScope.$digest();
25353           } catch (e) {
25354             $exceptionHandler(e);
25355             throw e;
25356           }
25357         }
25358       },
25359
25360       /**
25361        * @ngdoc method
25362        * @name $rootScope.Scope#$applyAsync
25363        * @kind function
25364        *
25365        * @description
25366        * Schedule the invocation of $apply to occur at a later time. The actual time difference
25367        * varies across browsers, but is typically around ~10 milliseconds.
25368        *
25369        * This can be used to queue up multiple expressions which need to be evaluated in the same
25370        * digest.
25371        *
25372        * @param {(string|function())=} exp An angular expression to be executed.
25373        *
25374        *    - `string`: execute using the rules as defined in {@link guide/expression expression}.
25375        *    - `function(scope)`: execute the function with current `scope` parameter.
25376        */
25377       $applyAsync: function(expr) {
25378         var scope = this;
25379         expr && applyAsyncQueue.push($applyAsyncExpression);
25380         scheduleApplyAsync();
25381
25382         function $applyAsyncExpression() {
25383           scope.$eval(expr);
25384         }
25385       },
25386
25387       /**
25388        * @ngdoc method
25389        * @name $rootScope.Scope#$on
25390        * @kind function
25391        *
25392        * @description
25393        * Listens on events of a given type. See {@link ng.$rootScope.Scope#$emit $emit} for
25394        * discussion of event life cycle.
25395        *
25396        * The event listener function format is: `function(event, args...)`. The `event` object
25397        * passed into the listener has the following attributes:
25398        *
25399        *   - `targetScope` - `{Scope}`: the scope on which the event was `$emit`-ed or
25400        *     `$broadcast`-ed.
25401        *   - `currentScope` - `{Scope}`: the scope that is currently handling the event. Once the
25402        *     event propagates through the scope hierarchy, this property is set to null.
25403        *   - `name` - `{string}`: name of the event.
25404        *   - `stopPropagation` - `{function=}`: calling `stopPropagation` function will cancel
25405        *     further event propagation (available only for events that were `$emit`-ed).
25406        *   - `preventDefault` - `{function}`: calling `preventDefault` sets `defaultPrevented` flag
25407        *     to true.
25408        *   - `defaultPrevented` - `{boolean}`: true if `preventDefault` was called.
25409        *
25410        * @param {string} name Event name to listen on.
25411        * @param {function(event, ...args)} listener Function to call when the event is emitted.
25412        * @returns {function()} Returns a deregistration function for this listener.
25413        */
25414       $on: function(name, listener) {
25415         var namedListeners = this.$$listeners[name];
25416         if (!namedListeners) {
25417           this.$$listeners[name] = namedListeners = [];
25418         }
25419         namedListeners.push(listener);
25420
25421         var current = this;
25422         do {
25423           if (!current.$$listenerCount[name]) {
25424             current.$$listenerCount[name] = 0;
25425           }
25426           current.$$listenerCount[name]++;
25427         } while ((current = current.$parent));
25428
25429         var self = this;
25430         return function() {
25431           var indexOfListener = namedListeners.indexOf(listener);
25432           if (indexOfListener !== -1) {
25433             namedListeners[indexOfListener] = null;
25434             decrementListenerCount(self, 1, name);
25435           }
25436         };
25437       },
25438
25439
25440       /**
25441        * @ngdoc method
25442        * @name $rootScope.Scope#$emit
25443        * @kind function
25444        *
25445        * @description
25446        * Dispatches an event `name` upwards through the scope hierarchy notifying the
25447        * registered {@link ng.$rootScope.Scope#$on} listeners.
25448        *
25449        * The event life cycle starts at the scope on which `$emit` was called. All
25450        * {@link ng.$rootScope.Scope#$on listeners} listening for `name` event on this scope get
25451        * notified. Afterwards, the event traverses upwards toward the root scope and calls all
25452        * registered listeners along the way. The event will stop propagating if one of the listeners
25453        * cancels it.
25454        *
25455        * Any exception emitted from the {@link ng.$rootScope.Scope#$on listeners} will be passed
25456        * onto the {@link ng.$exceptionHandler $exceptionHandler} service.
25457        *
25458        * @param {string} name Event name to emit.
25459        * @param {...*} args Optional one or more arguments which will be passed onto the event listeners.
25460        * @return {Object} Event object (see {@link ng.$rootScope.Scope#$on}).
25461        */
25462       $emit: function(name, args) {
25463         var empty = [],
25464             namedListeners,
25465             scope = this,
25466             stopPropagation = false,
25467             event = {
25468               name: name,
25469               targetScope: scope,
25470               stopPropagation: function() {stopPropagation = true;},
25471               preventDefault: function() {
25472                 event.defaultPrevented = true;
25473               },
25474               defaultPrevented: false
25475             },
25476             listenerArgs = concat([event], arguments, 1),
25477             i, length;
25478
25479         do {
25480           namedListeners = scope.$$listeners[name] || empty;
25481           event.currentScope = scope;
25482           for (i = 0, length = namedListeners.length; i < length; i++) {
25483
25484             // if listeners were deregistered, defragment the array
25485             if (!namedListeners[i]) {
25486               namedListeners.splice(i, 1);
25487               i--;
25488               length--;
25489               continue;
25490             }
25491             try {
25492               //allow all listeners attached to the current scope to run
25493               namedListeners[i].apply(null, listenerArgs);
25494             } catch (e) {
25495               $exceptionHandler(e);
25496             }
25497           }
25498           //if any listener on the current scope stops propagation, prevent bubbling
25499           if (stopPropagation) {
25500             event.currentScope = null;
25501             return event;
25502           }
25503           //traverse upwards
25504           scope = scope.$parent;
25505         } while (scope);
25506
25507         event.currentScope = null;
25508
25509         return event;
25510       },
25511
25512
25513       /**
25514        * @ngdoc method
25515        * @name $rootScope.Scope#$broadcast
25516        * @kind function
25517        *
25518        * @description
25519        * Dispatches an event `name` downwards to all child scopes (and their children) notifying the
25520        * registered {@link ng.$rootScope.Scope#$on} listeners.
25521        *
25522        * The event life cycle starts at the scope on which `$broadcast` was called. All
25523        * {@link ng.$rootScope.Scope#$on listeners} listening for `name` event on this scope get
25524        * notified. Afterwards, the event propagates to all direct and indirect scopes of the current
25525        * scope and calls all registered listeners along the way. The event cannot be canceled.
25526        *
25527        * Any exception emitted from the {@link ng.$rootScope.Scope#$on listeners} will be passed
25528        * onto the {@link ng.$exceptionHandler $exceptionHandler} service.
25529        *
25530        * @param {string} name Event name to broadcast.
25531        * @param {...*} args Optional one or more arguments which will be passed onto the event listeners.
25532        * @return {Object} Event object, see {@link ng.$rootScope.Scope#$on}
25533        */
25534       $broadcast: function(name, args) {
25535         var target = this,
25536             current = target,
25537             next = target,
25538             event = {
25539               name: name,
25540               targetScope: target,
25541               preventDefault: function() {
25542                 event.defaultPrevented = true;
25543               },
25544               defaultPrevented: false
25545             };
25546
25547         if (!target.$$listenerCount[name]) return event;
25548
25549         var listenerArgs = concat([event], arguments, 1),
25550             listeners, i, length;
25551
25552         //down while you can, then up and next sibling or up and next sibling until back at root
25553         while ((current = next)) {
25554           event.currentScope = current;
25555           listeners = current.$$listeners[name] || [];
25556           for (i = 0, length = listeners.length; i < length; i++) {
25557             // if listeners were deregistered, defragment the array
25558             if (!listeners[i]) {
25559               listeners.splice(i, 1);
25560               i--;
25561               length--;
25562               continue;
25563             }
25564
25565             try {
25566               listeners[i].apply(null, listenerArgs);
25567             } catch (e) {
25568               $exceptionHandler(e);
25569             }
25570           }
25571
25572           // Insanity Warning: scope depth-first traversal
25573           // yes, this code is a bit crazy, but it works and we have tests to prove it!
25574           // this piece should be kept in sync with the traversal in $digest
25575           // (though it differs due to having the extra check for $$listenerCount)
25576           if (!(next = ((current.$$listenerCount[name] && current.$$childHead) ||
25577               (current !== target && current.$$nextSibling)))) {
25578             while (current !== target && !(next = current.$$nextSibling)) {
25579               current = current.$parent;
25580             }
25581           }
25582         }
25583
25584         event.currentScope = null;
25585         return event;
25586       }
25587     };
25588
25589     var $rootScope = new Scope();
25590
25591     //The internal queues. Expose them on the $rootScope for debugging/testing purposes.
25592     var asyncQueue = $rootScope.$$asyncQueue = [];
25593     var postDigestQueue = $rootScope.$$postDigestQueue = [];
25594     var applyAsyncQueue = $rootScope.$$applyAsyncQueue = [];
25595
25596     return $rootScope;
25597
25598
25599     function beginPhase(phase) {
25600       if ($rootScope.$$phase) {
25601         throw $rootScopeMinErr('inprog', '{0} already in progress', $rootScope.$$phase);
25602       }
25603
25604       $rootScope.$$phase = phase;
25605     }
25606
25607     function clearPhase() {
25608       $rootScope.$$phase = null;
25609     }
25610
25611     function incrementWatchersCount(current, count) {
25612       do {
25613         current.$$watchersCount += count;
25614       } while ((current = current.$parent));
25615     }
25616
25617     function decrementListenerCount(current, count, name) {
25618       do {
25619         current.$$listenerCount[name] -= count;
25620
25621         if (current.$$listenerCount[name] === 0) {
25622           delete current.$$listenerCount[name];
25623         }
25624       } while ((current = current.$parent));
25625     }
25626
25627     /**
25628      * function used as an initial value for watchers.
25629      * because it's unique we can easily tell it apart from other values
25630      */
25631     function initWatchVal() {}
25632
25633     function flushApplyAsync() {
25634       while (applyAsyncQueue.length) {
25635         try {
25636           applyAsyncQueue.shift()();
25637         } catch (e) {
25638           $exceptionHandler(e);
25639         }
25640       }
25641       applyAsyncId = null;
25642     }
25643
25644     function scheduleApplyAsync() {
25645       if (applyAsyncId === null) {
25646         applyAsyncId = $browser.defer(function() {
25647           $rootScope.$apply(flushApplyAsync);
25648         });
25649       }
25650     }
25651   }];
25652 }
25653
25654 /**
25655  * @description
25656  * Private service to sanitize uris for links and images. Used by $compile and $sanitize.
25657  */
25658 function $$SanitizeUriProvider() {
25659   var aHrefSanitizationWhitelist = /^\s*(https?|ftp|mailto|tel|file):/,
25660     imgSrcSanitizationWhitelist = /^\s*((https?|ftp|file|blob):|data:image\/)/;
25661
25662   /**
25663    * @description
25664    * Retrieves or overrides the default regular expression that is used for whitelisting of safe
25665    * urls during a[href] sanitization.
25666    *
25667    * The sanitization is a security measure aimed at prevent XSS attacks via html links.
25668    *
25669    * Any url about to be assigned to a[href] via data-binding is first normalized and turned into
25670    * an absolute url. Afterwards, the url is matched against the `aHrefSanitizationWhitelist`
25671    * regular expression. If a match is found, the original url is written into the dom. Otherwise,
25672    * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM.
25673    *
25674    * @param {RegExp=} regexp New regexp to whitelist urls with.
25675    * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
25676    *    chaining otherwise.
25677    */
25678   this.aHrefSanitizationWhitelist = function(regexp) {
25679     if (isDefined(regexp)) {
25680       aHrefSanitizationWhitelist = regexp;
25681       return this;
25682     }
25683     return aHrefSanitizationWhitelist;
25684   };
25685
25686
25687   /**
25688    * @description
25689    * Retrieves or overrides the default regular expression that is used for whitelisting of safe
25690    * urls during img[src] sanitization.
25691    *
25692    * The sanitization is a security measure aimed at prevent XSS attacks via html links.
25693    *
25694    * Any url about to be assigned to img[src] via data-binding is first normalized and turned into
25695    * an absolute url. Afterwards, the url is matched against the `imgSrcSanitizationWhitelist`
25696    * regular expression. If a match is found, the original url is written into the dom. Otherwise,
25697    * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM.
25698    *
25699    * @param {RegExp=} regexp New regexp to whitelist urls with.
25700    * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
25701    *    chaining otherwise.
25702    */
25703   this.imgSrcSanitizationWhitelist = function(regexp) {
25704     if (isDefined(regexp)) {
25705       imgSrcSanitizationWhitelist = regexp;
25706       return this;
25707     }
25708     return imgSrcSanitizationWhitelist;
25709   };
25710
25711   this.$get = function() {
25712     return function sanitizeUri(uri, isImage) {
25713       var regex = isImage ? imgSrcSanitizationWhitelist : aHrefSanitizationWhitelist;
25714       var normalizedVal;
25715       normalizedVal = urlResolve(uri).href;
25716       if (normalizedVal !== '' && !normalizedVal.match(regex)) {
25717         return 'unsafe:' + normalizedVal;
25718       }
25719       return uri;
25720     };
25721   };
25722 }
25723
25724 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
25725  *     Any commits to this file should be reviewed with security in mind.  *
25726  *   Changes to this file can potentially create security vulnerabilities. *
25727  *          An approval from 2 Core members with history of modifying      *
25728  *                         this file is required.                          *
25729  *                                                                         *
25730  *  Does the change somehow allow for arbitrary javascript to be executed? *
25731  *    Or allows for someone to change the prototype of built-in objects?   *
25732  *     Or gives undesired access to variables likes document or window?    *
25733  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
25734
25735 var $sceMinErr = minErr('$sce');
25736
25737 var SCE_CONTEXTS = {
25738   HTML: 'html',
25739   CSS: 'css',
25740   URL: 'url',
25741   // RESOURCE_URL is a subtype of URL used in contexts where a privileged resource is sourced from a
25742   // url.  (e.g. ng-include, script src, templateUrl)
25743   RESOURCE_URL: 'resourceUrl',
25744   JS: 'js'
25745 };
25746
25747 // Helper functions follow.
25748
25749 function adjustMatcher(matcher) {
25750   if (matcher === 'self') {
25751     return matcher;
25752   } else if (isString(matcher)) {
25753     // Strings match exactly except for 2 wildcards - '*' and '**'.
25754     // '*' matches any character except those from the set ':/.?&'.
25755     // '**' matches any character (like .* in a RegExp).
25756     // More than 2 *'s raises an error as it's ill defined.
25757     if (matcher.indexOf('***') > -1) {
25758       throw $sceMinErr('iwcard',
25759           'Illegal sequence *** in string matcher.  String: {0}', matcher);
25760     }
25761     matcher = escapeForRegexp(matcher).
25762                   replace('\\*\\*', '.*').
25763                   replace('\\*', '[^:/.?&;]*');
25764     return new RegExp('^' + matcher + '$');
25765   } else if (isRegExp(matcher)) {
25766     // The only other type of matcher allowed is a Regexp.
25767     // Match entire URL / disallow partial matches.
25768     // Flags are reset (i.e. no global, ignoreCase or multiline)
25769     return new RegExp('^' + matcher.source + '$');
25770   } else {
25771     throw $sceMinErr('imatcher',
25772         'Matchers may only be "self", string patterns or RegExp objects');
25773   }
25774 }
25775
25776
25777 function adjustMatchers(matchers) {
25778   var adjustedMatchers = [];
25779   if (isDefined(matchers)) {
25780     forEach(matchers, function(matcher) {
25781       adjustedMatchers.push(adjustMatcher(matcher));
25782     });
25783   }
25784   return adjustedMatchers;
25785 }
25786
25787
25788 /**
25789  * @ngdoc service
25790  * @name $sceDelegate
25791  * @kind function
25792  *
25793  * @description
25794  *
25795  * `$sceDelegate` is a service that is used by the `$sce` service to provide {@link ng.$sce Strict
25796  * Contextual Escaping (SCE)} services to AngularJS.
25797  *
25798  * Typically, you would configure or override the {@link ng.$sceDelegate $sceDelegate} instead of
25799  * the `$sce` service to customize the way Strict Contextual Escaping works in AngularJS.  This is
25800  * because, while the `$sce` provides numerous shorthand methods, etc., you really only need to
25801  * override 3 core functions (`trustAs`, `getTrusted` and `valueOf`) to replace the way things
25802  * work because `$sce` delegates to `$sceDelegate` for these operations.
25803  *
25804  * Refer {@link ng.$sceDelegateProvider $sceDelegateProvider} to configure this service.
25805  *
25806  * The default instance of `$sceDelegate` should work out of the box with little pain.  While you
25807  * can override it completely to change the behavior of `$sce`, the common case would
25808  * involve configuring the {@link ng.$sceDelegateProvider $sceDelegateProvider} instead by setting
25809  * your own whitelists and blacklists for trusting URLs used for loading AngularJS resources such as
25810  * templates.  Refer {@link ng.$sceDelegateProvider#resourceUrlWhitelist
25811  * $sceDelegateProvider.resourceUrlWhitelist} and {@link
25812  * ng.$sceDelegateProvider#resourceUrlBlacklist $sceDelegateProvider.resourceUrlBlacklist}
25813  */
25814
25815 /**
25816  * @ngdoc provider
25817  * @name $sceDelegateProvider
25818  * @description
25819  *
25820  * The `$sceDelegateProvider` provider allows developers to configure the {@link ng.$sceDelegate
25821  * $sceDelegate} service.  This allows one to get/set the whitelists and blacklists used to ensure
25822  * that the URLs used for sourcing Angular templates are safe.  Refer {@link
25823  * ng.$sceDelegateProvider#resourceUrlWhitelist $sceDelegateProvider.resourceUrlWhitelist} and
25824  * {@link ng.$sceDelegateProvider#resourceUrlBlacklist $sceDelegateProvider.resourceUrlBlacklist}
25825  *
25826  * For the general details about this service in Angular, read the main page for {@link ng.$sce
25827  * Strict Contextual Escaping (SCE)}.
25828  *
25829  * **Example**:  Consider the following case. <a name="example"></a>
25830  *
25831  * - your app is hosted at url `http://myapp.example.com/`
25832  * - but some of your templates are hosted on other domains you control such as
25833  *   `http://srv01.assets.example.com/`,  `http://srv02.assets.example.com/`, etc.
25834  * - and you have an open redirect at `http://myapp.example.com/clickThru?...`.
25835  *
25836  * Here is what a secure configuration for this scenario might look like:
25837  *
25838  * ```
25839  *  angular.module('myApp', []).config(function($sceDelegateProvider) {
25840  *    $sceDelegateProvider.resourceUrlWhitelist([
25841  *      // Allow same origin resource loads.
25842  *      'self',
25843  *      // Allow loading from our assets domain.  Notice the difference between * and **.
25844  *      'http://srv*.assets.example.com/**'
25845  *    ]);
25846  *
25847  *    // The blacklist overrides the whitelist so the open redirect here is blocked.
25848  *    $sceDelegateProvider.resourceUrlBlacklist([
25849  *      'http://myapp.example.com/clickThru**'
25850  *    ]);
25851  *  });
25852  * ```
25853  */
25854
25855 function $SceDelegateProvider() {
25856   this.SCE_CONTEXTS = SCE_CONTEXTS;
25857
25858   // Resource URLs can also be trusted by policy.
25859   var resourceUrlWhitelist = ['self'],
25860       resourceUrlBlacklist = [];
25861
25862   /**
25863    * @ngdoc method
25864    * @name $sceDelegateProvider#resourceUrlWhitelist
25865    * @kind function
25866    *
25867    * @param {Array=} whitelist When provided, replaces the resourceUrlWhitelist with the value
25868    *     provided.  This must be an array or null.  A snapshot of this array is used so further
25869    *     changes to the array are ignored.
25870    *
25871    *     Follow {@link ng.$sce#resourceUrlPatternItem this link} for a description of the items
25872    *     allowed in this array.
25873    *
25874    *     Note: **an empty whitelist array will block all URLs**!
25875    *
25876    * @return {Array} the currently set whitelist array.
25877    *
25878    * The **default value** when no whitelist has been explicitly set is `['self']` allowing only
25879    * same origin resource requests.
25880    *
25881    * @description
25882    * Sets/Gets the whitelist of trusted resource URLs.
25883    */
25884   this.resourceUrlWhitelist = function(value) {
25885     if (arguments.length) {
25886       resourceUrlWhitelist = adjustMatchers(value);
25887     }
25888     return resourceUrlWhitelist;
25889   };
25890
25891   /**
25892    * @ngdoc method
25893    * @name $sceDelegateProvider#resourceUrlBlacklist
25894    * @kind function
25895    *
25896    * @param {Array=} blacklist When provided, replaces the resourceUrlBlacklist with the value
25897    *     provided.  This must be an array or null.  A snapshot of this array is used so further
25898    *     changes to the array are ignored.
25899    *
25900    *     Follow {@link ng.$sce#resourceUrlPatternItem this link} for a description of the items
25901    *     allowed in this array.
25902    *
25903    *     The typical usage for the blacklist is to **block
25904    *     [open redirects](http://cwe.mitre.org/data/definitions/601.html)** served by your domain as
25905    *     these would otherwise be trusted but actually return content from the redirected domain.
25906    *
25907    *     Finally, **the blacklist overrides the whitelist** and has the final say.
25908    *
25909    * @return {Array} the currently set blacklist array.
25910    *
25911    * The **default value** when no whitelist has been explicitly set is the empty array (i.e. there
25912    * is no blacklist.)
25913    *
25914    * @description
25915    * Sets/Gets the blacklist of trusted resource URLs.
25916    */
25917
25918   this.resourceUrlBlacklist = function(value) {
25919     if (arguments.length) {
25920       resourceUrlBlacklist = adjustMatchers(value);
25921     }
25922     return resourceUrlBlacklist;
25923   };
25924
25925   this.$get = ['$injector', function($injector) {
25926
25927     var htmlSanitizer = function htmlSanitizer(html) {
25928       throw $sceMinErr('unsafe', 'Attempting to use an unsafe value in a safe context.');
25929     };
25930
25931     if ($injector.has('$sanitize')) {
25932       htmlSanitizer = $injector.get('$sanitize');
25933     }
25934
25935
25936     function matchUrl(matcher, parsedUrl) {
25937       if (matcher === 'self') {
25938         return urlIsSameOrigin(parsedUrl);
25939       } else {
25940         // definitely a regex.  See adjustMatchers()
25941         return !!matcher.exec(parsedUrl.href);
25942       }
25943     }
25944
25945     function isResourceUrlAllowedByPolicy(url) {
25946       var parsedUrl = urlResolve(url.toString());
25947       var i, n, allowed = false;
25948       // Ensure that at least one item from the whitelist allows this url.
25949       for (i = 0, n = resourceUrlWhitelist.length; i < n; i++) {
25950         if (matchUrl(resourceUrlWhitelist[i], parsedUrl)) {
25951           allowed = true;
25952           break;
25953         }
25954       }
25955       if (allowed) {
25956         // Ensure that no item from the blacklist blocked this url.
25957         for (i = 0, n = resourceUrlBlacklist.length; i < n; i++) {
25958           if (matchUrl(resourceUrlBlacklist[i], parsedUrl)) {
25959             allowed = false;
25960             break;
25961           }
25962         }
25963       }
25964       return allowed;
25965     }
25966
25967     function generateHolderType(Base) {
25968       var holderType = function TrustedValueHolderType(trustedValue) {
25969         this.$$unwrapTrustedValue = function() {
25970           return trustedValue;
25971         };
25972       };
25973       if (Base) {
25974         holderType.prototype = new Base();
25975       }
25976       holderType.prototype.valueOf = function sceValueOf() {
25977         return this.$$unwrapTrustedValue();
25978       };
25979       holderType.prototype.toString = function sceToString() {
25980         return this.$$unwrapTrustedValue().toString();
25981       };
25982       return holderType;
25983     }
25984
25985     var trustedValueHolderBase = generateHolderType(),
25986         byType = {};
25987
25988     byType[SCE_CONTEXTS.HTML] = generateHolderType(trustedValueHolderBase);
25989     byType[SCE_CONTEXTS.CSS] = generateHolderType(trustedValueHolderBase);
25990     byType[SCE_CONTEXTS.URL] = generateHolderType(trustedValueHolderBase);
25991     byType[SCE_CONTEXTS.JS] = generateHolderType(trustedValueHolderBase);
25992     byType[SCE_CONTEXTS.RESOURCE_URL] = generateHolderType(byType[SCE_CONTEXTS.URL]);
25993
25994     /**
25995      * @ngdoc method
25996      * @name $sceDelegate#trustAs
25997      *
25998      * @description
25999      * Returns an object that is trusted by angular for use in specified strict
26000      * contextual escaping contexts (such as ng-bind-html, ng-include, any src
26001      * attribute interpolation, any dom event binding attribute interpolation
26002      * such as for onclick,  etc.) that uses the provided value.
26003      * See {@link ng.$sce $sce} for enabling strict contextual escaping.
26004      *
26005      * @param {string} type The kind of context in which this value is safe for use.  e.g. url,
26006      *   resourceUrl, html, js and css.
26007      * @param {*} value The value that that should be considered trusted/safe.
26008      * @returns {*} A value that can be used to stand in for the provided `value` in places
26009      * where Angular expects a $sce.trustAs() return value.
26010      */
26011     function trustAs(type, trustedValue) {
26012       var Constructor = (byType.hasOwnProperty(type) ? byType[type] : null);
26013       if (!Constructor) {
26014         throw $sceMinErr('icontext',
26015             'Attempted to trust a value in invalid context. Context: {0}; Value: {1}',
26016             type, trustedValue);
26017       }
26018       if (trustedValue === null || isUndefined(trustedValue) || trustedValue === '') {
26019         return trustedValue;
26020       }
26021       // All the current contexts in SCE_CONTEXTS happen to be strings.  In order to avoid trusting
26022       // mutable objects, we ensure here that the value passed in is actually a string.
26023       if (typeof trustedValue !== 'string') {
26024         throw $sceMinErr('itype',
26025             'Attempted to trust a non-string value in a content requiring a string: Context: {0}',
26026             type);
26027       }
26028       return new Constructor(trustedValue);
26029     }
26030
26031     /**
26032      * @ngdoc method
26033      * @name $sceDelegate#valueOf
26034      *
26035      * @description
26036      * If the passed parameter had been returned by a prior call to {@link ng.$sceDelegate#trustAs
26037      * `$sceDelegate.trustAs`}, returns the value that had been passed to {@link
26038      * ng.$sceDelegate#trustAs `$sceDelegate.trustAs`}.
26039      *
26040      * If the passed parameter is not a value that had been returned by {@link
26041      * ng.$sceDelegate#trustAs `$sceDelegate.trustAs`}, returns it as-is.
26042      *
26043      * @param {*} value The result of a prior {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs`}
26044      *      call or anything else.
26045      * @returns {*} The `value` that was originally provided to {@link ng.$sceDelegate#trustAs
26046      *     `$sceDelegate.trustAs`} if `value` is the result of such a call.  Otherwise, returns
26047      *     `value` unchanged.
26048      */
26049     function valueOf(maybeTrusted) {
26050       if (maybeTrusted instanceof trustedValueHolderBase) {
26051         return maybeTrusted.$$unwrapTrustedValue();
26052       } else {
26053         return maybeTrusted;
26054       }
26055     }
26056
26057     /**
26058      * @ngdoc method
26059      * @name $sceDelegate#getTrusted
26060      *
26061      * @description
26062      * Takes the result of a {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs`} call and
26063      * returns the originally supplied value if the queried context type is a supertype of the
26064      * created type.  If this condition isn't satisfied, throws an exception.
26065      *
26066      * @param {string} type The kind of context in which this value is to be used.
26067      * @param {*} maybeTrusted The result of a prior {@link ng.$sceDelegate#trustAs
26068      *     `$sceDelegate.trustAs`} call.
26069      * @returns {*} The value the was originally provided to {@link ng.$sceDelegate#trustAs
26070      *     `$sceDelegate.trustAs`} if valid in this context.  Otherwise, throws an exception.
26071      */
26072     function getTrusted(type, maybeTrusted) {
26073       if (maybeTrusted === null || isUndefined(maybeTrusted) || maybeTrusted === '') {
26074         return maybeTrusted;
26075       }
26076       var constructor = (byType.hasOwnProperty(type) ? byType[type] : null);
26077       if (constructor && maybeTrusted instanceof constructor) {
26078         return maybeTrusted.$$unwrapTrustedValue();
26079       }
26080       // If we get here, then we may only take one of two actions.
26081       // 1. sanitize the value for the requested type, or
26082       // 2. throw an exception.
26083       if (type === SCE_CONTEXTS.RESOURCE_URL) {
26084         if (isResourceUrlAllowedByPolicy(maybeTrusted)) {
26085           return maybeTrusted;
26086         } else {
26087           throw $sceMinErr('insecurl',
26088               'Blocked loading resource from url not allowed by $sceDelegate policy.  URL: {0}',
26089               maybeTrusted.toString());
26090         }
26091       } else if (type === SCE_CONTEXTS.HTML) {
26092         return htmlSanitizer(maybeTrusted);
26093       }
26094       throw $sceMinErr('unsafe', 'Attempting to use an unsafe value in a safe context.');
26095     }
26096
26097     return { trustAs: trustAs,
26098              getTrusted: getTrusted,
26099              valueOf: valueOf };
26100   }];
26101 }
26102
26103
26104 /**
26105  * @ngdoc provider
26106  * @name $sceProvider
26107  * @description
26108  *
26109  * The $sceProvider provider allows developers to configure the {@link ng.$sce $sce} service.
26110  * -   enable/disable Strict Contextual Escaping (SCE) in a module
26111  * -   override the default implementation with a custom delegate
26112  *
26113  * Read more about {@link ng.$sce Strict Contextual Escaping (SCE)}.
26114  */
26115
26116 /* jshint maxlen: false*/
26117
26118 /**
26119  * @ngdoc service
26120  * @name $sce
26121  * @kind function
26122  *
26123  * @description
26124  *
26125  * `$sce` is a service that provides Strict Contextual Escaping services to AngularJS.
26126  *
26127  * # Strict Contextual Escaping
26128  *
26129  * Strict Contextual Escaping (SCE) is a mode in which AngularJS requires bindings in certain
26130  * contexts to result in a value that is marked as safe to use for that context.  One example of
26131  * such a context is binding arbitrary html controlled by the user via `ng-bind-html`.  We refer
26132  * to these contexts as privileged or SCE contexts.
26133  *
26134  * As of version 1.2, Angular ships with SCE enabled by default.
26135  *
26136  * Note:  When enabled (the default), IE<11 in quirks mode is not supported.  In this mode, IE<11 allow
26137  * one to execute arbitrary javascript by the use of the expression() syntax.  Refer
26138  * <http://blogs.msdn.com/b/ie/archive/2008/10/16/ending-expressions.aspx> to learn more about them.
26139  * You can ensure your document is in standards mode and not quirks mode by adding `<!doctype html>`
26140  * to the top of your HTML document.
26141  *
26142  * SCE assists in writing code in way that (a) is secure by default and (b) makes auditing for
26143  * security vulnerabilities such as XSS, clickjacking, etc. a lot easier.
26144  *
26145  * Here's an example of a binding in a privileged context:
26146  *
26147  * ```
26148  * <input ng-model="userHtml" aria-label="User input">
26149  * <div ng-bind-html="userHtml"></div>
26150  * ```
26151  *
26152  * Notice that `ng-bind-html` is bound to `userHtml` controlled by the user.  With SCE
26153  * disabled, this application allows the user to render arbitrary HTML into the DIV.
26154  * In a more realistic example, one may be rendering user comments, blog articles, etc. via
26155  * bindings.  (HTML is just one example of a context where rendering user controlled input creates
26156  * security vulnerabilities.)
26157  *
26158  * For the case of HTML, you might use a library, either on the client side, or on the server side,
26159  * to sanitize unsafe HTML before binding to the value and rendering it in the document.
26160  *
26161  * How would you ensure that every place that used these types of bindings was bound to a value that
26162  * was sanitized by your library (or returned as safe for rendering by your server?)  How can you
26163  * ensure that you didn't accidentally delete the line that sanitized the value, or renamed some
26164  * properties/fields and forgot to update the binding to the sanitized value?
26165  *
26166  * To be secure by default, you want to ensure that any such bindings are disallowed unless you can
26167  * determine that something explicitly says it's safe to use a value for binding in that
26168  * context.  You can then audit your code (a simple grep would do) to ensure that this is only done
26169  * for those values that you can easily tell are safe - because they were received from your server,
26170  * sanitized by your library, etc.  You can organize your codebase to help with this - perhaps
26171  * allowing only the files in a specific directory to do this.  Ensuring that the internal API
26172  * exposed by that code doesn't markup arbitrary values as safe then becomes a more manageable task.
26173  *
26174  * In the case of AngularJS' SCE service, one uses {@link ng.$sce#trustAs $sce.trustAs}
26175  * (and shorthand methods such as {@link ng.$sce#trustAsHtml $sce.trustAsHtml}, etc.) to
26176  * obtain values that will be accepted by SCE / privileged contexts.
26177  *
26178  *
26179  * ## How does it work?
26180  *
26181  * In privileged contexts, directives and code will bind to the result of {@link ng.$sce#getTrusted
26182  * $sce.getTrusted(context, value)} rather than to the value directly.  Directives use {@link
26183  * ng.$sce#parseAs $sce.parseAs} rather than `$parse` to watch attribute bindings, which performs the
26184  * {@link ng.$sce#getTrusted $sce.getTrusted} behind the scenes on non-constant literals.
26185  *
26186  * As an example, {@link ng.directive:ngBindHtml ngBindHtml} uses {@link
26187  * ng.$sce#parseAsHtml $sce.parseAsHtml(binding expression)}.  Here's the actual code (slightly
26188  * simplified):
26189  *
26190  * ```
26191  * var ngBindHtmlDirective = ['$sce', function($sce) {
26192  *   return function(scope, element, attr) {
26193  *     scope.$watch($sce.parseAsHtml(attr.ngBindHtml), function(value) {
26194  *       element.html(value || '');
26195  *     });
26196  *   };
26197  * }];
26198  * ```
26199  *
26200  * ## Impact on loading templates
26201  *
26202  * This applies both to the {@link ng.directive:ngInclude `ng-include`} directive as well as
26203  * `templateUrl`'s specified by {@link guide/directive directives}.
26204  *
26205  * By default, Angular only loads templates from the same domain and protocol as the application
26206  * document.  This is done by calling {@link ng.$sce#getTrustedResourceUrl
26207  * $sce.getTrustedResourceUrl} on the template URL.  To load templates from other domains and/or
26208  * protocols, you may either {@link ng.$sceDelegateProvider#resourceUrlWhitelist whitelist
26209  * them} or {@link ng.$sce#trustAsResourceUrl wrap it} into a trusted value.
26210  *
26211  * *Please note*:
26212  * The browser's
26213  * [Same Origin Policy](https://code.google.com/p/browsersec/wiki/Part2#Same-origin_policy_for_XMLHttpRequest)
26214  * and [Cross-Origin Resource Sharing (CORS)](http://www.w3.org/TR/cors/)
26215  * policy apply in addition to this and may further restrict whether the template is successfully
26216  * loaded.  This means that without the right CORS policy, loading templates from a different domain
26217  * won't work on all browsers.  Also, loading templates from `file://` URL does not work on some
26218  * browsers.
26219  *
26220  * ## This feels like too much overhead
26221  *
26222  * It's important to remember that SCE only applies to interpolation expressions.
26223  *
26224  * If your expressions are constant literals, they're automatically trusted and you don't need to
26225  * call `$sce.trustAs` on them (remember to include the `ngSanitize` module) (e.g.
26226  * `<div ng-bind-html="'<b>implicitly trusted</b>'"></div>`) just works.
26227  *
26228  * Additionally, `a[href]` and `img[src]` automatically sanitize their URLs and do not pass them
26229  * through {@link ng.$sce#getTrusted $sce.getTrusted}.  SCE doesn't play a role here.
26230  *
26231  * The included {@link ng.$sceDelegate $sceDelegate} comes with sane defaults to allow you to load
26232  * templates in `ng-include` from your application's domain without having to even know about SCE.
26233  * It blocks loading templates from other domains or loading templates over http from an https
26234  * served document.  You can change these by setting your own custom {@link
26235  * ng.$sceDelegateProvider#resourceUrlWhitelist whitelists} and {@link
26236  * ng.$sceDelegateProvider#resourceUrlBlacklist blacklists} for matching such URLs.
26237  *
26238  * This significantly reduces the overhead.  It is far easier to pay the small overhead and have an
26239  * application that's secure and can be audited to verify that with much more ease than bolting
26240  * security onto an application later.
26241  *
26242  * <a name="contexts"></a>
26243  * ## What trusted context types are supported?
26244  *
26245  * | Context             | Notes          |
26246  * |---------------------|----------------|
26247  * | `$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. |
26248  * | `$sce.CSS`          | For CSS that's safe to source into the application.  Currently unused.  Feel free to use it in your own directives. |
26249  * | `$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. |
26250  * | `$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. |
26251  * | `$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. |
26252  *
26253  * ## Format of items in {@link ng.$sceDelegateProvider#resourceUrlWhitelist resourceUrlWhitelist}/{@link ng.$sceDelegateProvider#resourceUrlBlacklist Blacklist} <a name="resourceUrlPatternItem"></a>
26254  *
26255  *  Each element in these arrays must be one of the following:
26256  *
26257  *  - **'self'**
26258  *    - The special **string**, `'self'`, can be used to match against all URLs of the **same
26259  *      domain** as the application document using the **same protocol**.
26260  *  - **String** (except the special value `'self'`)
26261  *    - The string is matched against the full *normalized / absolute URL* of the resource
26262  *      being tested (substring matches are not good enough.)
26263  *    - There are exactly **two wildcard sequences** - `*` and `**`.  All other characters
26264  *      match themselves.
26265  *    - `*`: matches zero or more occurrences of any character other than one of the following 6
26266  *      characters: '`:`', '`/`', '`.`', '`?`', '`&`' and '`;`'.  It's a useful wildcard for use
26267  *      in a whitelist.
26268  *    - `**`: matches zero or more occurrences of *any* character.  As such, it's not
26269  *      appropriate for use in a scheme, domain, etc. as it would match too much.  (e.g.
26270  *      http://**.example.com/ would match http://evil.com/?ignore=.example.com/ and that might
26271  *      not have been the intention.)  Its usage at the very end of the path is ok.  (e.g.
26272  *      http://foo.example.com/templates/**).
26273  *  - **RegExp** (*see caveat below*)
26274  *    - *Caveat*:  While regular expressions are powerful and offer great flexibility,  their syntax
26275  *      (and all the inevitable escaping) makes them *harder to maintain*.  It's easy to
26276  *      accidentally introduce a bug when one updates a complex expression (imho, all regexes should
26277  *      have good test coverage).  For instance, the use of `.` in the regex is correct only in a
26278  *      small number of cases.  A `.` character in the regex used when matching the scheme or a
26279  *      subdomain could be matched against a `:` or literal `.` that was likely not intended.   It
26280  *      is highly recommended to use the string patterns and only fall back to regular expressions
26281  *      as a last resort.
26282  *    - The regular expression must be an instance of RegExp (i.e. not a string.)  It is
26283  *      matched against the **entire** *normalized / absolute URL* of the resource being tested
26284  *      (even when the RegExp did not have the `^` and `$` codes.)  In addition, any flags
26285  *      present on the RegExp (such as multiline, global, ignoreCase) are ignored.
26286  *    - If you are generating your JavaScript from some other templating engine (not
26287  *      recommended, e.g. in issue [#4006](https://github.com/angular/angular.js/issues/4006)),
26288  *      remember to escape your regular expression (and be aware that you might need more than
26289  *      one level of escaping depending on your templating engine and the way you interpolated
26290  *      the value.)  Do make use of your platform's escaping mechanism as it might be good
26291  *      enough before coding your own.  E.g. Ruby has
26292  *      [Regexp.escape(str)](http://www.ruby-doc.org/core-2.0.0/Regexp.html#method-c-escape)
26293  *      and Python has [re.escape](http://docs.python.org/library/re.html#re.escape).
26294  *      Javascript lacks a similar built in function for escaping.  Take a look at Google
26295  *      Closure library's [goog.string.regExpEscape(s)](
26296  *      http://docs.closure-library.googlecode.com/git/closure_goog_string_string.js.source.html#line962).
26297  *
26298  * Refer {@link ng.$sceDelegateProvider $sceDelegateProvider} for an example.
26299  *
26300  * ## Show me an example using SCE.
26301  *
26302  * <example module="mySceApp" deps="angular-sanitize.js">
26303  * <file name="index.html">
26304  *   <div ng-controller="AppController as myCtrl">
26305  *     <i ng-bind-html="myCtrl.explicitlyTrustedHtml" id="explicitlyTrustedHtml"></i><br><br>
26306  *     <b>User comments</b><br>
26307  *     By default, HTML that isn't explicitly trusted (e.g. Alice's comment) is sanitized when
26308  *     $sanitize is available.  If $sanitize isn't available, this results in an error instead of an
26309  *     exploit.
26310  *     <div class="well">
26311  *       <div ng-repeat="userComment in myCtrl.userComments">
26312  *         <b>{{userComment.name}}</b>:
26313  *         <span ng-bind-html="userComment.htmlComment" class="htmlComment"></span>
26314  *         <br>
26315  *       </div>
26316  *     </div>
26317  *   </div>
26318  * </file>
26319  *
26320  * <file name="script.js">
26321  *   angular.module('mySceApp', ['ngSanitize'])
26322  *     .controller('AppController', ['$http', '$templateCache', '$sce',
26323  *       function($http, $templateCache, $sce) {
26324  *         var self = this;
26325  *         $http.get("test_data.json", {cache: $templateCache}).success(function(userComments) {
26326  *           self.userComments = userComments;
26327  *         });
26328  *         self.explicitlyTrustedHtml = $sce.trustAsHtml(
26329  *             '<span onmouseover="this.textContent=&quot;Explicitly trusted HTML bypasses ' +
26330  *             'sanitization.&quot;">Hover over this text.</span>');
26331  *       }]);
26332  * </file>
26333  *
26334  * <file name="test_data.json">
26335  * [
26336  *   { "name": "Alice",
26337  *     "htmlComment":
26338  *         "<span onmouseover='this.textContent=\"PWN3D!\"'>Is <i>anyone</i> reading this?</span>"
26339  *   },
26340  *   { "name": "Bob",
26341  *     "htmlComment": "<i>Yes!</i>  Am I the only other one?"
26342  *   }
26343  * ]
26344  * </file>
26345  *
26346  * <file name="protractor.js" type="protractor">
26347  *   describe('SCE doc demo', function() {
26348  *     it('should sanitize untrusted values', function() {
26349  *       expect(element.all(by.css('.htmlComment')).first().getInnerHtml())
26350  *           .toBe('<span>Is <i>anyone</i> reading this?</span>');
26351  *     });
26352  *
26353  *     it('should NOT sanitize explicitly trusted values', function() {
26354  *       expect(element(by.id('explicitlyTrustedHtml')).getInnerHtml()).toBe(
26355  *           '<span onmouseover="this.textContent=&quot;Explicitly trusted HTML bypasses ' +
26356  *           'sanitization.&quot;">Hover over this text.</span>');
26357  *     });
26358  *   });
26359  * </file>
26360  * </example>
26361  *
26362  *
26363  *
26364  * ## Can I disable SCE completely?
26365  *
26366  * Yes, you can.  However, this is strongly discouraged.  SCE gives you a lot of security benefits
26367  * for little coding overhead.  It will be much harder to take an SCE disabled application and
26368  * either secure it on your own or enable SCE at a later stage.  It might make sense to disable SCE
26369  * for cases where you have a lot of existing code that was written before SCE was introduced and
26370  * you're migrating them a module at a time.
26371  *
26372  * That said, here's how you can completely disable SCE:
26373  *
26374  * ```
26375  * angular.module('myAppWithSceDisabledmyApp', []).config(function($sceProvider) {
26376  *   // Completely disable SCE.  For demonstration purposes only!
26377  *   // Do not use in new projects.
26378  *   $sceProvider.enabled(false);
26379  * });
26380  * ```
26381  *
26382  */
26383 /* jshint maxlen: 100 */
26384
26385 function $SceProvider() {
26386   var enabled = true;
26387
26388   /**
26389    * @ngdoc method
26390    * @name $sceProvider#enabled
26391    * @kind function
26392    *
26393    * @param {boolean=} value If provided, then enables/disables SCE.
26394    * @return {boolean} true if SCE is enabled, false otherwise.
26395    *
26396    * @description
26397    * Enables/disables SCE and returns the current value.
26398    */
26399   this.enabled = function(value) {
26400     if (arguments.length) {
26401       enabled = !!value;
26402     }
26403     return enabled;
26404   };
26405
26406
26407   /* Design notes on the default implementation for SCE.
26408    *
26409    * The API contract for the SCE delegate
26410    * -------------------------------------
26411    * The SCE delegate object must provide the following 3 methods:
26412    *
26413    * - trustAs(contextEnum, value)
26414    *     This method is used to tell the SCE service that the provided value is OK to use in the
26415    *     contexts specified by contextEnum.  It must return an object that will be accepted by
26416    *     getTrusted() for a compatible contextEnum and return this value.
26417    *
26418    * - valueOf(value)
26419    *     For values that were not produced by trustAs(), return them as is.  For values that were
26420    *     produced by trustAs(), return the corresponding input value to trustAs.  Basically, if
26421    *     trustAs is wrapping the given values into some type, this operation unwraps it when given
26422    *     such a value.
26423    *
26424    * - getTrusted(contextEnum, value)
26425    *     This function should return the a value that is safe to use in the context specified by
26426    *     contextEnum or throw and exception otherwise.
26427    *
26428    * NOTE: This contract deliberately does NOT state that values returned by trustAs() must be
26429    * opaque or wrapped in some holder object.  That happens to be an implementation detail.  For
26430    * instance, an implementation could maintain a registry of all trusted objects by context.  In
26431    * such a case, trustAs() would return the same object that was passed in.  getTrusted() would
26432    * return the same object passed in if it was found in the registry under a compatible context or
26433    * throw an exception otherwise.  An implementation might only wrap values some of the time based
26434    * on some criteria.  getTrusted() might return a value and not throw an exception for special
26435    * constants or objects even if not wrapped.  All such implementations fulfill this contract.
26436    *
26437    *
26438    * A note on the inheritance model for SCE contexts
26439    * ------------------------------------------------
26440    * I've used inheritance and made RESOURCE_URL wrapped types a subtype of URL wrapped types.  This
26441    * is purely an implementation details.
26442    *
26443    * The contract is simply this:
26444    *
26445    *     getTrusted($sce.RESOURCE_URL, value) succeeding implies that getTrusted($sce.URL, value)
26446    *     will also succeed.
26447    *
26448    * Inheritance happens to capture this in a natural way.  In some future, we
26449    * may not use inheritance anymore.  That is OK because no code outside of
26450    * sce.js and sceSpecs.js would need to be aware of this detail.
26451    */
26452
26453   this.$get = ['$parse', '$sceDelegate', function(
26454                 $parse,   $sceDelegate) {
26455     // Prereq: Ensure that we're not running in IE<11 quirks mode.  In that mode, IE < 11 allow
26456     // the "expression(javascript expression)" syntax which is insecure.
26457     if (enabled && msie < 8) {
26458       throw $sceMinErr('iequirks',
26459         'Strict Contextual Escaping does not support Internet Explorer version < 11 in quirks ' +
26460         'mode.  You can fix this by adding the text <!doctype html> to the top of your HTML ' +
26461         'document.  See http://docs.angularjs.org/api/ng.$sce for more information.');
26462     }
26463
26464     var sce = shallowCopy(SCE_CONTEXTS);
26465
26466     /**
26467      * @ngdoc method
26468      * @name $sce#isEnabled
26469      * @kind function
26470      *
26471      * @return {Boolean} true if SCE is enabled, false otherwise.  If you want to set the value, you
26472      * have to do it at module config time on {@link ng.$sceProvider $sceProvider}.
26473      *
26474      * @description
26475      * Returns a boolean indicating if SCE is enabled.
26476      */
26477     sce.isEnabled = function() {
26478       return enabled;
26479     };
26480     sce.trustAs = $sceDelegate.trustAs;
26481     sce.getTrusted = $sceDelegate.getTrusted;
26482     sce.valueOf = $sceDelegate.valueOf;
26483
26484     if (!enabled) {
26485       sce.trustAs = sce.getTrusted = function(type, value) { return value; };
26486       sce.valueOf = identity;
26487     }
26488
26489     /**
26490      * @ngdoc method
26491      * @name $sce#parseAs
26492      *
26493      * @description
26494      * Converts Angular {@link guide/expression expression} into a function.  This is like {@link
26495      * ng.$parse $parse} and is identical when the expression is a literal constant.  Otherwise, it
26496      * wraps the expression in a call to {@link ng.$sce#getTrusted $sce.getTrusted(*type*,
26497      * *result*)}
26498      *
26499      * @param {string} type The kind of SCE context in which this result will be used.
26500      * @param {string} expression String expression to compile.
26501      * @returns {function(context, locals)} a function which represents the compiled expression:
26502      *
26503      *    * `context` – `{object}` – an object against which any expressions embedded in the strings
26504      *      are evaluated against (typically a scope object).
26505      *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
26506      *      `context`.
26507      */
26508     sce.parseAs = function sceParseAs(type, expr) {
26509       var parsed = $parse(expr);
26510       if (parsed.literal && parsed.constant) {
26511         return parsed;
26512       } else {
26513         return $parse(expr, function(value) {
26514           return sce.getTrusted(type, value);
26515         });
26516       }
26517     };
26518
26519     /**
26520      * @ngdoc method
26521      * @name $sce#trustAs
26522      *
26523      * @description
26524      * Delegates to {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs`}.  As such,
26525      * returns an object that is trusted by angular for use in specified strict contextual
26526      * escaping contexts (such as ng-bind-html, ng-include, any src attribute
26527      * interpolation, any dom event binding attribute interpolation such as for onclick,  etc.)
26528      * that uses the provided value.  See * {@link ng.$sce $sce} for enabling strict contextual
26529      * escaping.
26530      *
26531      * @param {string} type The kind of context in which this value is safe for use.  e.g. url,
26532      *   resourceUrl, html, js and css.
26533      * @param {*} value The value that that should be considered trusted/safe.
26534      * @returns {*} A value that can be used to stand in for the provided `value` in places
26535      * where Angular expects a $sce.trustAs() return value.
26536      */
26537
26538     /**
26539      * @ngdoc method
26540      * @name $sce#trustAsHtml
26541      *
26542      * @description
26543      * Shorthand method.  `$sce.trustAsHtml(value)` →
26544      *     {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.HTML, value)`}
26545      *
26546      * @param {*} value The value to trustAs.
26547      * @returns {*} An object that can be passed to {@link ng.$sce#getTrustedHtml
26548      *     $sce.getTrustedHtml(value)} to obtain the original value.  (privileged directives
26549      *     only accept expressions that are either literal constants or are the
26550      *     return value of {@link ng.$sce#trustAs $sce.trustAs}.)
26551      */
26552
26553     /**
26554      * @ngdoc method
26555      * @name $sce#trustAsUrl
26556      *
26557      * @description
26558      * Shorthand method.  `$sce.trustAsUrl(value)` →
26559      *     {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.URL, value)`}
26560      *
26561      * @param {*} value The value to trustAs.
26562      * @returns {*} An object that can be passed to {@link ng.$sce#getTrustedUrl
26563      *     $sce.getTrustedUrl(value)} to obtain the original value.  (privileged directives
26564      *     only accept expressions that are either literal constants or are the
26565      *     return value of {@link ng.$sce#trustAs $sce.trustAs}.)
26566      */
26567
26568     /**
26569      * @ngdoc method
26570      * @name $sce#trustAsResourceUrl
26571      *
26572      * @description
26573      * Shorthand method.  `$sce.trustAsResourceUrl(value)` →
26574      *     {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.RESOURCE_URL, value)`}
26575      *
26576      * @param {*} value The value to trustAs.
26577      * @returns {*} An object that can be passed to {@link ng.$sce#getTrustedResourceUrl
26578      *     $sce.getTrustedResourceUrl(value)} to obtain the original value.  (privileged directives
26579      *     only accept expressions that are either literal constants or are the return
26580      *     value of {@link ng.$sce#trustAs $sce.trustAs}.)
26581      */
26582
26583     /**
26584      * @ngdoc method
26585      * @name $sce#trustAsJs
26586      *
26587      * @description
26588      * Shorthand method.  `$sce.trustAsJs(value)` →
26589      *     {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.JS, value)`}
26590      *
26591      * @param {*} value The value to trustAs.
26592      * @returns {*} An object that can be passed to {@link ng.$sce#getTrustedJs
26593      *     $sce.getTrustedJs(value)} to obtain the original value.  (privileged directives
26594      *     only accept expressions that are either literal constants or are the
26595      *     return value of {@link ng.$sce#trustAs $sce.trustAs}.)
26596      */
26597
26598     /**
26599      * @ngdoc method
26600      * @name $sce#getTrusted
26601      *
26602      * @description
26603      * Delegates to {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted`}.  As such,
26604      * takes the result of a {@link ng.$sce#trustAs `$sce.trustAs`}() call and returns the
26605      * originally supplied value if the queried context type is a supertype of the created type.
26606      * If this condition isn't satisfied, throws an exception.
26607      *
26608      * @param {string} type The kind of context in which this value is to be used.
26609      * @param {*} maybeTrusted The result of a prior {@link ng.$sce#trustAs `$sce.trustAs`}
26610      *                         call.
26611      * @returns {*} The value the was originally provided to
26612      *              {@link ng.$sce#trustAs `$sce.trustAs`} if valid in this context.
26613      *              Otherwise, throws an exception.
26614      */
26615
26616     /**
26617      * @ngdoc method
26618      * @name $sce#getTrustedHtml
26619      *
26620      * @description
26621      * Shorthand method.  `$sce.getTrustedHtml(value)` →
26622      *     {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.HTML, value)`}
26623      *
26624      * @param {*} value The value to pass to `$sce.getTrusted`.
26625      * @returns {*} The return value of `$sce.getTrusted($sce.HTML, value)`
26626      */
26627
26628     /**
26629      * @ngdoc method
26630      * @name $sce#getTrustedCss
26631      *
26632      * @description
26633      * Shorthand method.  `$sce.getTrustedCss(value)` →
26634      *     {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.CSS, value)`}
26635      *
26636      * @param {*} value The value to pass to `$sce.getTrusted`.
26637      * @returns {*} The return value of `$sce.getTrusted($sce.CSS, value)`
26638      */
26639
26640     /**
26641      * @ngdoc method
26642      * @name $sce#getTrustedUrl
26643      *
26644      * @description
26645      * Shorthand method.  `$sce.getTrustedUrl(value)` →
26646      *     {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.URL, value)`}
26647      *
26648      * @param {*} value The value to pass to `$sce.getTrusted`.
26649      * @returns {*} The return value of `$sce.getTrusted($sce.URL, value)`
26650      */
26651
26652     /**
26653      * @ngdoc method
26654      * @name $sce#getTrustedResourceUrl
26655      *
26656      * @description
26657      * Shorthand method.  `$sce.getTrustedResourceUrl(value)` →
26658      *     {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.RESOURCE_URL, value)`}
26659      *
26660      * @param {*} value The value to pass to `$sceDelegate.getTrusted`.
26661      * @returns {*} The return value of `$sce.getTrusted($sce.RESOURCE_URL, value)`
26662      */
26663
26664     /**
26665      * @ngdoc method
26666      * @name $sce#getTrustedJs
26667      *
26668      * @description
26669      * Shorthand method.  `$sce.getTrustedJs(value)` →
26670      *     {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.JS, value)`}
26671      *
26672      * @param {*} value The value to pass to `$sce.getTrusted`.
26673      * @returns {*} The return value of `$sce.getTrusted($sce.JS, value)`
26674      */
26675
26676     /**
26677      * @ngdoc method
26678      * @name $sce#parseAsHtml
26679      *
26680      * @description
26681      * Shorthand method.  `$sce.parseAsHtml(expression string)` →
26682      *     {@link ng.$sce#parseAs `$sce.parseAs($sce.HTML, value)`}
26683      *
26684      * @param {string} expression String expression to compile.
26685      * @returns {function(context, locals)} a function which represents the compiled expression:
26686      *
26687      *    * `context` – `{object}` – an object against which any expressions embedded in the strings
26688      *      are evaluated against (typically a scope object).
26689      *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
26690      *      `context`.
26691      */
26692
26693     /**
26694      * @ngdoc method
26695      * @name $sce#parseAsCss
26696      *
26697      * @description
26698      * Shorthand method.  `$sce.parseAsCss(value)` →
26699      *     {@link ng.$sce#parseAs `$sce.parseAs($sce.CSS, value)`}
26700      *
26701      * @param {string} expression String expression to compile.
26702      * @returns {function(context, locals)} a function which represents the compiled expression:
26703      *
26704      *    * `context` – `{object}` – an object against which any expressions embedded in the strings
26705      *      are evaluated against (typically a scope object).
26706      *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
26707      *      `context`.
26708      */
26709
26710     /**
26711      * @ngdoc method
26712      * @name $sce#parseAsUrl
26713      *
26714      * @description
26715      * Shorthand method.  `$sce.parseAsUrl(value)` →
26716      *     {@link ng.$sce#parseAs `$sce.parseAs($sce.URL, value)`}
26717      *
26718      * @param {string} expression String expression to compile.
26719      * @returns {function(context, locals)} a function which represents the compiled expression:
26720      *
26721      *    * `context` – `{object}` – an object against which any expressions embedded in the strings
26722      *      are evaluated against (typically a scope object).
26723      *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
26724      *      `context`.
26725      */
26726
26727     /**
26728      * @ngdoc method
26729      * @name $sce#parseAsResourceUrl
26730      *
26731      * @description
26732      * Shorthand method.  `$sce.parseAsResourceUrl(value)` →
26733      *     {@link ng.$sce#parseAs `$sce.parseAs($sce.RESOURCE_URL, value)`}
26734      *
26735      * @param {string} expression String expression to compile.
26736      * @returns {function(context, locals)} a function which represents the compiled expression:
26737      *
26738      *    * `context` – `{object}` – an object against which any expressions embedded in the strings
26739      *      are evaluated against (typically a scope object).
26740      *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
26741      *      `context`.
26742      */
26743
26744     /**
26745      * @ngdoc method
26746      * @name $sce#parseAsJs
26747      *
26748      * @description
26749      * Shorthand method.  `$sce.parseAsJs(value)` →
26750      *     {@link ng.$sce#parseAs `$sce.parseAs($sce.JS, value)`}
26751      *
26752      * @param {string} expression String expression to compile.
26753      * @returns {function(context, locals)} a function which represents the compiled expression:
26754      *
26755      *    * `context` – `{object}` – an object against which any expressions embedded in the strings
26756      *      are evaluated against (typically a scope object).
26757      *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
26758      *      `context`.
26759      */
26760
26761     // Shorthand delegations.
26762     var parse = sce.parseAs,
26763         getTrusted = sce.getTrusted,
26764         trustAs = sce.trustAs;
26765
26766     forEach(SCE_CONTEXTS, function(enumValue, name) {
26767       var lName = lowercase(name);
26768       sce[camelCase("parse_as_" + lName)] = function(expr) {
26769         return parse(enumValue, expr);
26770       };
26771       sce[camelCase("get_trusted_" + lName)] = function(value) {
26772         return getTrusted(enumValue, value);
26773       };
26774       sce[camelCase("trust_as_" + lName)] = function(value) {
26775         return trustAs(enumValue, value);
26776       };
26777     });
26778
26779     return sce;
26780   }];
26781 }
26782
26783 /**
26784  * !!! This is an undocumented "private" service !!!
26785  *
26786  * @name $sniffer
26787  * @requires $window
26788  * @requires $document
26789  *
26790  * @property {boolean} history Does the browser support html5 history api ?
26791  * @property {boolean} transitions Does the browser support CSS transition events ?
26792  * @property {boolean} animations Does the browser support CSS animation events ?
26793  *
26794  * @description
26795  * This is very simple implementation of testing browser's features.
26796  */
26797 function $SnifferProvider() {
26798   this.$get = ['$window', '$document', function($window, $document) {
26799     var eventSupport = {},
26800         android =
26801           toInt((/android (\d+)/.exec(lowercase(($window.navigator || {}).userAgent)) || [])[1]),
26802         boxee = /Boxee/i.test(($window.navigator || {}).userAgent),
26803         document = $document[0] || {},
26804         vendorPrefix,
26805         vendorRegex = /^(Moz|webkit|ms)(?=[A-Z])/,
26806         bodyStyle = document.body && document.body.style,
26807         transitions = false,
26808         animations = false,
26809         match;
26810
26811     if (bodyStyle) {
26812       for (var prop in bodyStyle) {
26813         if (match = vendorRegex.exec(prop)) {
26814           vendorPrefix = match[0];
26815           vendorPrefix = vendorPrefix.substr(0, 1).toUpperCase() + vendorPrefix.substr(1);
26816           break;
26817         }
26818       }
26819
26820       if (!vendorPrefix) {
26821         vendorPrefix = ('WebkitOpacity' in bodyStyle) && 'webkit';
26822       }
26823
26824       transitions = !!(('transition' in bodyStyle) || (vendorPrefix + 'Transition' in bodyStyle));
26825       animations  = !!(('animation' in bodyStyle) || (vendorPrefix + 'Animation' in bodyStyle));
26826
26827       if (android && (!transitions ||  !animations)) {
26828         transitions = isString(bodyStyle.webkitTransition);
26829         animations = isString(bodyStyle.webkitAnimation);
26830       }
26831     }
26832
26833
26834     return {
26835       // Android has history.pushState, but it does not update location correctly
26836       // so let's not use the history API at all.
26837       // http://code.google.com/p/android/issues/detail?id=17471
26838       // https://github.com/angular/angular.js/issues/904
26839
26840       // older webkit browser (533.9) on Boxee box has exactly the same problem as Android has
26841       // so let's not use the history API also
26842       // We are purposefully using `!(android < 4)` to cover the case when `android` is undefined
26843       // jshint -W018
26844       history: !!($window.history && $window.history.pushState && !(android < 4) && !boxee),
26845       // jshint +W018
26846       hasEvent: function(event) {
26847         // IE9 implements 'input' event it's so fubared that we rather pretend that it doesn't have
26848         // it. In particular the event is not fired when backspace or delete key are pressed or
26849         // when cut operation is performed.
26850         // IE10+ implements 'input' event but it erroneously fires under various situations,
26851         // e.g. when placeholder changes, or a form is focused.
26852         if (event === 'input' && msie <= 11) return false;
26853
26854         if (isUndefined(eventSupport[event])) {
26855           var divElm = document.createElement('div');
26856           eventSupport[event] = 'on' + event in divElm;
26857         }
26858
26859         return eventSupport[event];
26860       },
26861       csp: csp(),
26862       vendorPrefix: vendorPrefix,
26863       transitions: transitions,
26864       animations: animations,
26865       android: android
26866     };
26867   }];
26868 }
26869
26870 var $compileMinErr = minErr('$compile');
26871
26872 /**
26873  * @ngdoc service
26874  * @name $templateRequest
26875  *
26876  * @description
26877  * The `$templateRequest` service runs security checks then downloads the provided template using
26878  * `$http` and, upon success, stores the contents inside of `$templateCache`. If the HTTP request
26879  * fails or the response data of the HTTP request is empty, a `$compile` error will be thrown (the
26880  * exception can be thwarted by setting the 2nd parameter of the function to true). Note that the
26881  * contents of `$templateCache` are trusted, so the call to `$sce.getTrustedUrl(tpl)` is omitted
26882  * when `tpl` is of type string and `$templateCache` has the matching entry.
26883  *
26884  * @param {string|TrustedResourceUrl} tpl The HTTP request template URL
26885  * @param {boolean=} ignoreRequestError Whether or not to ignore the exception when the request fails or the template is empty
26886  *
26887  * @return {Promise} a promise for the HTTP response data of the given URL.
26888  *
26889  * @property {number} totalPendingRequests total amount of pending template requests being downloaded.
26890  */
26891 function $TemplateRequestProvider() {
26892   this.$get = ['$templateCache', '$http', '$q', '$sce', function($templateCache, $http, $q, $sce) {
26893     function handleRequestFn(tpl, ignoreRequestError) {
26894       handleRequestFn.totalPendingRequests++;
26895
26896       // We consider the template cache holds only trusted templates, so
26897       // there's no need to go through whitelisting again for keys that already
26898       // are included in there. This also makes Angular accept any script
26899       // directive, no matter its name. However, we still need to unwrap trusted
26900       // types.
26901       if (!isString(tpl) || !$templateCache.get(tpl)) {
26902         tpl = $sce.getTrustedResourceUrl(tpl);
26903       }
26904
26905       var transformResponse = $http.defaults && $http.defaults.transformResponse;
26906
26907       if (isArray(transformResponse)) {
26908         transformResponse = transformResponse.filter(function(transformer) {
26909           return transformer !== defaultHttpResponseTransform;
26910         });
26911       } else if (transformResponse === defaultHttpResponseTransform) {
26912         transformResponse = null;
26913       }
26914
26915       var httpOptions = {
26916         cache: $templateCache,
26917         transformResponse: transformResponse
26918       };
26919
26920       return $http.get(tpl, httpOptions)
26921         ['finally'](function() {
26922           handleRequestFn.totalPendingRequests--;
26923         })
26924         .then(function(response) {
26925           $templateCache.put(tpl, response.data);
26926           return response.data;
26927         }, handleError);
26928
26929       function handleError(resp) {
26930         if (!ignoreRequestError) {
26931           throw $compileMinErr('tpload', 'Failed to load template: {0} (HTTP status: {1} {2})',
26932             tpl, resp.status, resp.statusText);
26933         }
26934         return $q.reject(resp);
26935       }
26936     }
26937
26938     handleRequestFn.totalPendingRequests = 0;
26939
26940     return handleRequestFn;
26941   }];
26942 }
26943
26944 function $$TestabilityProvider() {
26945   this.$get = ['$rootScope', '$browser', '$location',
26946        function($rootScope,   $browser,   $location) {
26947
26948     /**
26949      * @name $testability
26950      *
26951      * @description
26952      * The private $$testability service provides a collection of methods for use when debugging
26953      * or by automated test and debugging tools.
26954      */
26955     var testability = {};
26956
26957     /**
26958      * @name $$testability#findBindings
26959      *
26960      * @description
26961      * Returns an array of elements that are bound (via ng-bind or {{}})
26962      * to expressions matching the input.
26963      *
26964      * @param {Element} element The element root to search from.
26965      * @param {string} expression The binding expression to match.
26966      * @param {boolean} opt_exactMatch If true, only returns exact matches
26967      *     for the expression. Filters and whitespace are ignored.
26968      */
26969     testability.findBindings = function(element, expression, opt_exactMatch) {
26970       var bindings = element.getElementsByClassName('ng-binding');
26971       var matches = [];
26972       forEach(bindings, function(binding) {
26973         var dataBinding = angular.element(binding).data('$binding');
26974         if (dataBinding) {
26975           forEach(dataBinding, function(bindingName) {
26976             if (opt_exactMatch) {
26977               var matcher = new RegExp('(^|\\s)' + escapeForRegexp(expression) + '(\\s|\\||$)');
26978               if (matcher.test(bindingName)) {
26979                 matches.push(binding);
26980               }
26981             } else {
26982               if (bindingName.indexOf(expression) != -1) {
26983                 matches.push(binding);
26984               }
26985             }
26986           });
26987         }
26988       });
26989       return matches;
26990     };
26991
26992     /**
26993      * @name $$testability#findModels
26994      *
26995      * @description
26996      * Returns an array of elements that are two-way found via ng-model to
26997      * expressions matching the input.
26998      *
26999      * @param {Element} element The element root to search from.
27000      * @param {string} expression The model expression to match.
27001      * @param {boolean} opt_exactMatch If true, only returns exact matches
27002      *     for the expression.
27003      */
27004     testability.findModels = function(element, expression, opt_exactMatch) {
27005       var prefixes = ['ng-', 'data-ng-', 'ng\\:'];
27006       for (var p = 0; p < prefixes.length; ++p) {
27007         var attributeEquals = opt_exactMatch ? '=' : '*=';
27008         var selector = '[' + prefixes[p] + 'model' + attributeEquals + '"' + expression + '"]';
27009         var elements = element.querySelectorAll(selector);
27010         if (elements.length) {
27011           return elements;
27012         }
27013       }
27014     };
27015
27016     /**
27017      * @name $$testability#getLocation
27018      *
27019      * @description
27020      * Shortcut for getting the location in a browser agnostic way. Returns
27021      *     the path, search, and hash. (e.g. /path?a=b#hash)
27022      */
27023     testability.getLocation = function() {
27024       return $location.url();
27025     };
27026
27027     /**
27028      * @name $$testability#setLocation
27029      *
27030      * @description
27031      * Shortcut for navigating to a location without doing a full page reload.
27032      *
27033      * @param {string} url The location url (path, search and hash,
27034      *     e.g. /path?a=b#hash) to go to.
27035      */
27036     testability.setLocation = function(url) {
27037       if (url !== $location.url()) {
27038         $location.url(url);
27039         $rootScope.$digest();
27040       }
27041     };
27042
27043     /**
27044      * @name $$testability#whenStable
27045      *
27046      * @description
27047      * Calls the callback when $timeout and $http requests are completed.
27048      *
27049      * @param {function} callback
27050      */
27051     testability.whenStable = function(callback) {
27052       $browser.notifyWhenNoOutstandingRequests(callback);
27053     };
27054
27055     return testability;
27056   }];
27057 }
27058
27059 function $TimeoutProvider() {
27060   this.$get = ['$rootScope', '$browser', '$q', '$$q', '$exceptionHandler',
27061        function($rootScope,   $browser,   $q,   $$q,   $exceptionHandler) {
27062
27063     var deferreds = {};
27064
27065
27066      /**
27067       * @ngdoc service
27068       * @name $timeout
27069       *
27070       * @description
27071       * Angular's wrapper for `window.setTimeout`. The `fn` function is wrapped into a try/catch
27072       * block and delegates any exceptions to
27073       * {@link ng.$exceptionHandler $exceptionHandler} service.
27074       *
27075       * The return value of calling `$timeout` is a promise, which will be resolved when
27076       * the delay has passed and the timeout function, if provided, is executed.
27077       *
27078       * To cancel a timeout request, call `$timeout.cancel(promise)`.
27079       *
27080       * In tests you can use {@link ngMock.$timeout `$timeout.flush()`} to
27081       * synchronously flush the queue of deferred functions.
27082       *
27083       * If you only want a promise that will be resolved after some specified delay
27084       * then you can call `$timeout` without the `fn` function.
27085       *
27086       * @param {function()=} fn A function, whose execution should be delayed.
27087       * @param {number=} [delay=0] Delay in milliseconds.
27088       * @param {boolean=} [invokeApply=true] If set to `false` skips model dirty checking, otherwise
27089       *   will invoke `fn` within the {@link ng.$rootScope.Scope#$apply $apply} block.
27090       * @param {...*=} Pass additional parameters to the executed function.
27091       * @returns {Promise} Promise that will be resolved when the timeout is reached. The value this
27092       *   promise will be resolved with is the return value of the `fn` function.
27093       *
27094       */
27095     function timeout(fn, delay, invokeApply) {
27096       if (!isFunction(fn)) {
27097         invokeApply = delay;
27098         delay = fn;
27099         fn = noop;
27100       }
27101
27102       var args = sliceArgs(arguments, 3),
27103           skipApply = (isDefined(invokeApply) && !invokeApply),
27104           deferred = (skipApply ? $$q : $q).defer(),
27105           promise = deferred.promise,
27106           timeoutId;
27107
27108       timeoutId = $browser.defer(function() {
27109         try {
27110           deferred.resolve(fn.apply(null, args));
27111         } catch (e) {
27112           deferred.reject(e);
27113           $exceptionHandler(e);
27114         }
27115         finally {
27116           delete deferreds[promise.$$timeoutId];
27117         }
27118
27119         if (!skipApply) $rootScope.$apply();
27120       }, delay);
27121
27122       promise.$$timeoutId = timeoutId;
27123       deferreds[timeoutId] = deferred;
27124
27125       return promise;
27126     }
27127
27128
27129      /**
27130       * @ngdoc method
27131       * @name $timeout#cancel
27132       *
27133       * @description
27134       * Cancels a task associated with the `promise`. As a result of this, the promise will be
27135       * resolved with a rejection.
27136       *
27137       * @param {Promise=} promise Promise returned by the `$timeout` function.
27138       * @returns {boolean} Returns `true` if the task hasn't executed yet and was successfully
27139       *   canceled.
27140       */
27141     timeout.cancel = function(promise) {
27142       if (promise && promise.$$timeoutId in deferreds) {
27143         deferreds[promise.$$timeoutId].reject('canceled');
27144         delete deferreds[promise.$$timeoutId];
27145         return $browser.defer.cancel(promise.$$timeoutId);
27146       }
27147       return false;
27148     };
27149
27150     return timeout;
27151   }];
27152 }
27153
27154 // NOTE:  The usage of window and document instead of $window and $document here is
27155 // deliberate.  This service depends on the specific behavior of anchor nodes created by the
27156 // browser (resolving and parsing URLs) that is unlikely to be provided by mock objects and
27157 // cause us to break tests.  In addition, when the browser resolves a URL for XHR, it
27158 // doesn't know about mocked locations and resolves URLs to the real document - which is
27159 // exactly the behavior needed here.  There is little value is mocking these out for this
27160 // service.
27161 var urlParsingNode = document.createElement("a");
27162 var originUrl = urlResolve(window.location.href);
27163
27164
27165 /**
27166  *
27167  * Implementation Notes for non-IE browsers
27168  * ----------------------------------------
27169  * Assigning a URL to the href property of an anchor DOM node, even one attached to the DOM,
27170  * results both in the normalizing and parsing of the URL.  Normalizing means that a relative
27171  * URL will be resolved into an absolute URL in the context of the application document.
27172  * Parsing means that the anchor node's host, hostname, protocol, port, pathname and related
27173  * properties are all populated to reflect the normalized URL.  This approach has wide
27174  * compatibility - Safari 1+, Mozilla 1+, Opera 7+,e etc.  See
27175  * http://www.aptana.com/reference/html/api/HTMLAnchorElement.html
27176  *
27177  * Implementation Notes for IE
27178  * ---------------------------
27179  * IE <= 10 normalizes the URL when assigned to the anchor node similar to the other
27180  * browsers.  However, the parsed components will not be set if the URL assigned did not specify
27181  * them.  (e.g. if you assign a.href = "foo", then a.protocol, a.host, etc. will be empty.)  We
27182  * work around that by performing the parsing in a 2nd step by taking a previously normalized
27183  * URL (e.g. by assigning to a.href) and assigning it a.href again.  This correctly populates the
27184  * properties such as protocol, hostname, port, etc.
27185  *
27186  * References:
27187  *   http://developer.mozilla.org/en-US/docs/Web/API/HTMLAnchorElement
27188  *   http://www.aptana.com/reference/html/api/HTMLAnchorElement.html
27189  *   http://url.spec.whatwg.org/#urlutils
27190  *   https://github.com/angular/angular.js/pull/2902
27191  *   http://james.padolsey.com/javascript/parsing-urls-with-the-dom/
27192  *
27193  * @kind function
27194  * @param {string} url The URL to be parsed.
27195  * @description Normalizes and parses a URL.
27196  * @returns {object} Returns the normalized URL as a dictionary.
27197  *
27198  *   | member name   | Description    |
27199  *   |---------------|----------------|
27200  *   | href          | A normalized version of the provided URL if it was not an absolute URL |
27201  *   | protocol      | The protocol including the trailing colon                              |
27202  *   | host          | The host and port (if the port is non-default) of the normalizedUrl    |
27203  *   | search        | The search params, minus the question mark                             |
27204  *   | hash          | The hash string, minus the hash symbol
27205  *   | hostname      | The hostname
27206  *   | port          | The port, without ":"
27207  *   | pathname      | The pathname, beginning with "/"
27208  *
27209  */
27210 function urlResolve(url) {
27211   var href = url;
27212
27213   if (msie) {
27214     // Normalize before parse.  Refer Implementation Notes on why this is
27215     // done in two steps on IE.
27216     urlParsingNode.setAttribute("href", href);
27217     href = urlParsingNode.href;
27218   }
27219
27220   urlParsingNode.setAttribute('href', href);
27221
27222   // urlParsingNode provides the UrlUtils interface - http://url.spec.whatwg.org/#urlutils
27223   return {
27224     href: urlParsingNode.href,
27225     protocol: urlParsingNode.protocol ? urlParsingNode.protocol.replace(/:$/, '') : '',
27226     host: urlParsingNode.host,
27227     search: urlParsingNode.search ? urlParsingNode.search.replace(/^\?/, '') : '',
27228     hash: urlParsingNode.hash ? urlParsingNode.hash.replace(/^#/, '') : '',
27229     hostname: urlParsingNode.hostname,
27230     port: urlParsingNode.port,
27231     pathname: (urlParsingNode.pathname.charAt(0) === '/')
27232       ? urlParsingNode.pathname
27233       : '/' + urlParsingNode.pathname
27234   };
27235 }
27236
27237 /**
27238  * Parse a request URL and determine whether this is a same-origin request as the application document.
27239  *
27240  * @param {string|object} requestUrl The url of the request as a string that will be resolved
27241  * or a parsed URL object.
27242  * @returns {boolean} Whether the request is for the same origin as the application document.
27243  */
27244 function urlIsSameOrigin(requestUrl) {
27245   var parsed = (isString(requestUrl)) ? urlResolve(requestUrl) : requestUrl;
27246   return (parsed.protocol === originUrl.protocol &&
27247           parsed.host === originUrl.host);
27248 }
27249
27250 /**
27251  * @ngdoc service
27252  * @name $window
27253  *
27254  * @description
27255  * A reference to the browser's `window` object. While `window`
27256  * is globally available in JavaScript, it causes testability problems, because
27257  * it is a global variable. In angular we always refer to it through the
27258  * `$window` service, so it may be overridden, removed or mocked for testing.
27259  *
27260  * Expressions, like the one defined for the `ngClick` directive in the example
27261  * below, are evaluated with respect to the current scope.  Therefore, there is
27262  * no risk of inadvertently coding in a dependency on a global value in such an
27263  * expression.
27264  *
27265  * @example
27266    <example module="windowExample">
27267      <file name="index.html">
27268        <script>
27269          angular.module('windowExample', [])
27270            .controller('ExampleController', ['$scope', '$window', function($scope, $window) {
27271              $scope.greeting = 'Hello, World!';
27272              $scope.doGreeting = function(greeting) {
27273                $window.alert(greeting);
27274              };
27275            }]);
27276        </script>
27277        <div ng-controller="ExampleController">
27278          <input type="text" ng-model="greeting" aria-label="greeting" />
27279          <button ng-click="doGreeting(greeting)">ALERT</button>
27280        </div>
27281      </file>
27282      <file name="protractor.js" type="protractor">
27283       it('should display the greeting in the input box', function() {
27284        element(by.model('greeting')).sendKeys('Hello, E2E Tests');
27285        // If we click the button it will block the test runner
27286        // element(':button').click();
27287       });
27288      </file>
27289    </example>
27290  */
27291 function $WindowProvider() {
27292   this.$get = valueFn(window);
27293 }
27294
27295 /**
27296  * @name $$cookieReader
27297  * @requires $document
27298  *
27299  * @description
27300  * This is a private service for reading cookies used by $http and ngCookies
27301  *
27302  * @return {Object} a key/value map of the current cookies
27303  */
27304 function $$CookieReader($document) {
27305   var rawDocument = $document[0] || {};
27306   var lastCookies = {};
27307   var lastCookieString = '';
27308
27309   function safeDecodeURIComponent(str) {
27310     try {
27311       return decodeURIComponent(str);
27312     } catch (e) {
27313       return str;
27314     }
27315   }
27316
27317   return function() {
27318     var cookieArray, cookie, i, index, name;
27319     var currentCookieString = rawDocument.cookie || '';
27320
27321     if (currentCookieString !== lastCookieString) {
27322       lastCookieString = currentCookieString;
27323       cookieArray = lastCookieString.split('; ');
27324       lastCookies = {};
27325
27326       for (i = 0; i < cookieArray.length; i++) {
27327         cookie = cookieArray[i];
27328         index = cookie.indexOf('=');
27329         if (index > 0) { //ignore nameless cookies
27330           name = safeDecodeURIComponent(cookie.substring(0, index));
27331           // the first value that is seen for a cookie is the most
27332           // specific one.  values for the same cookie name that
27333           // follow are for less specific paths.
27334           if (isUndefined(lastCookies[name])) {
27335             lastCookies[name] = safeDecodeURIComponent(cookie.substring(index + 1));
27336           }
27337         }
27338       }
27339     }
27340     return lastCookies;
27341   };
27342 }
27343
27344 $$CookieReader.$inject = ['$document'];
27345
27346 function $$CookieReaderProvider() {
27347   this.$get = $$CookieReader;
27348 }
27349
27350 /* global currencyFilter: true,
27351  dateFilter: true,
27352  filterFilter: true,
27353  jsonFilter: true,
27354  limitToFilter: true,
27355  lowercaseFilter: true,
27356  numberFilter: true,
27357  orderByFilter: true,
27358  uppercaseFilter: true,
27359  */
27360
27361 /**
27362  * @ngdoc provider
27363  * @name $filterProvider
27364  * @description
27365  *
27366  * Filters are just functions which transform input to an output. However filters need to be
27367  * Dependency Injected. To achieve this a filter definition consists of a factory function which is
27368  * annotated with dependencies and is responsible for creating a filter function.
27369  *
27370  * <div class="alert alert-warning">
27371  * **Note:** Filter names must be valid angular {@link expression} identifiers, such as `uppercase` or `orderBy`.
27372  * Names with special characters, such as hyphens and dots, are not allowed. If you wish to namespace
27373  * your filters, then you can use capitalization (`myappSubsectionFilterx`) or underscores
27374  * (`myapp_subsection_filterx`).
27375  * </div>
27376  *
27377  * ```js
27378  *   // Filter registration
27379  *   function MyModule($provide, $filterProvider) {
27380  *     // create a service to demonstrate injection (not always needed)
27381  *     $provide.value('greet', function(name){
27382  *       return 'Hello ' + name + '!';
27383  *     });
27384  *
27385  *     // register a filter factory which uses the
27386  *     // greet service to demonstrate DI.
27387  *     $filterProvider.register('greet', function(greet){
27388  *       // return the filter function which uses the greet service
27389  *       // to generate salutation
27390  *       return function(text) {
27391  *         // filters need to be forgiving so check input validity
27392  *         return text && greet(text) || text;
27393  *       };
27394  *     });
27395  *   }
27396  * ```
27397  *
27398  * The filter function is registered with the `$injector` under the filter name suffix with
27399  * `Filter`.
27400  *
27401  * ```js
27402  *   it('should be the same instance', inject(
27403  *     function($filterProvider) {
27404  *       $filterProvider.register('reverse', function(){
27405  *         return ...;
27406  *       });
27407  *     },
27408  *     function($filter, reverseFilter) {
27409  *       expect($filter('reverse')).toBe(reverseFilter);
27410  *     });
27411  * ```
27412  *
27413  *
27414  * For more information about how angular filters work, and how to create your own filters, see
27415  * {@link guide/filter Filters} in the Angular Developer Guide.
27416  */
27417
27418 /**
27419  * @ngdoc service
27420  * @name $filter
27421  * @kind function
27422  * @description
27423  * Filters are used for formatting data displayed to the user.
27424  *
27425  * The general syntax in templates is as follows:
27426  *
27427  *         {{ expression [| filter_name[:parameter_value] ... ] }}
27428  *
27429  * @param {String} name Name of the filter function to retrieve
27430  * @return {Function} the filter function
27431  * @example
27432    <example name="$filter" module="filterExample">
27433      <file name="index.html">
27434        <div ng-controller="MainCtrl">
27435         <h3>{{ originalText }}</h3>
27436         <h3>{{ filteredText }}</h3>
27437        </div>
27438      </file>
27439
27440      <file name="script.js">
27441       angular.module('filterExample', [])
27442       .controller('MainCtrl', function($scope, $filter) {
27443         $scope.originalText = 'hello';
27444         $scope.filteredText = $filter('uppercase')($scope.originalText);
27445       });
27446      </file>
27447    </example>
27448   */
27449 $FilterProvider.$inject = ['$provide'];
27450 function $FilterProvider($provide) {
27451   var suffix = 'Filter';
27452
27453   /**
27454    * @ngdoc method
27455    * @name $filterProvider#register
27456    * @param {string|Object} name Name of the filter function, or an object map of filters where
27457    *    the keys are the filter names and the values are the filter factories.
27458    *
27459    *    <div class="alert alert-warning">
27460    *    **Note:** Filter names must be valid angular {@link expression} identifiers, such as `uppercase` or `orderBy`.
27461    *    Names with special characters, such as hyphens and dots, are not allowed. If you wish to namespace
27462    *    your filters, then you can use capitalization (`myappSubsectionFilterx`) or underscores
27463    *    (`myapp_subsection_filterx`).
27464    *    </div>
27465     * @param {Function} factory If the first argument was a string, a factory function for the filter to be registered.
27466    * @returns {Object} Registered filter instance, or if a map of filters was provided then a map
27467    *    of the registered filter instances.
27468    */
27469   function register(name, factory) {
27470     if (isObject(name)) {
27471       var filters = {};
27472       forEach(name, function(filter, key) {
27473         filters[key] = register(key, filter);
27474       });
27475       return filters;
27476     } else {
27477       return $provide.factory(name + suffix, factory);
27478     }
27479   }
27480   this.register = register;
27481
27482   this.$get = ['$injector', function($injector) {
27483     return function(name) {
27484       return $injector.get(name + suffix);
27485     };
27486   }];
27487
27488   ////////////////////////////////////////
27489
27490   /* global
27491     currencyFilter: false,
27492     dateFilter: false,
27493     filterFilter: false,
27494     jsonFilter: false,
27495     limitToFilter: false,
27496     lowercaseFilter: false,
27497     numberFilter: false,
27498     orderByFilter: false,
27499     uppercaseFilter: false,
27500   */
27501
27502   register('currency', currencyFilter);
27503   register('date', dateFilter);
27504   register('filter', filterFilter);
27505   register('json', jsonFilter);
27506   register('limitTo', limitToFilter);
27507   register('lowercase', lowercaseFilter);
27508   register('number', numberFilter);
27509   register('orderBy', orderByFilter);
27510   register('uppercase', uppercaseFilter);
27511 }
27512
27513 /**
27514  * @ngdoc filter
27515  * @name filter
27516  * @kind function
27517  *
27518  * @description
27519  * Selects a subset of items from `array` and returns it as a new array.
27520  *
27521  * @param {Array} array The source array.
27522  * @param {string|Object|function()} expression The predicate to be used for selecting items from
27523  *   `array`.
27524  *
27525  *   Can be one of:
27526  *
27527  *   - `string`: The string is used for matching against the contents of the `array`. All strings or
27528  *     objects with string properties in `array` that match this string will be returned. This also
27529  *     applies to nested object properties.
27530  *     The predicate can be negated by prefixing the string with `!`.
27531  *
27532  *   - `Object`: A pattern object can be used to filter specific properties on objects contained
27533  *     by `array`. For example `{name:"M", phone:"1"}` predicate will return an array of items
27534  *     which have property `name` containing "M" and property `phone` containing "1". A special
27535  *     property name `$` can be used (as in `{$:"text"}`) to accept a match against any
27536  *     property of the object or its nested object properties. That's equivalent to the simple
27537  *     substring match with a `string` as described above. The predicate can be negated by prefixing
27538  *     the string with `!`.
27539  *     For example `{name: "!M"}` predicate will return an array of items which have property `name`
27540  *     not containing "M".
27541  *
27542  *     Note that a named property will match properties on the same level only, while the special
27543  *     `$` property will match properties on the same level or deeper. E.g. an array item like
27544  *     `{name: {first: 'John', last: 'Doe'}}` will **not** be matched by `{name: 'John'}`, but
27545  *     **will** be matched by `{$: 'John'}`.
27546  *
27547  *   - `function(value, index, array)`: A predicate function can be used to write arbitrary filters.
27548  *     The function is called for each element of the array, with the element, its index, and
27549  *     the entire array itself as arguments.
27550  *
27551  *     The final result is an array of those elements that the predicate returned true for.
27552  *
27553  * @param {function(actual, expected)|true|undefined} comparator Comparator which is used in
27554  *     determining if the expected value (from the filter expression) and actual value (from
27555  *     the object in the array) should be considered a match.
27556  *
27557  *   Can be one of:
27558  *
27559  *   - `function(actual, expected)`:
27560  *     The function will be given the object value and the predicate value to compare and
27561  *     should return true if both values should be considered equal.
27562  *
27563  *   - `true`: A shorthand for `function(actual, expected) { return angular.equals(actual, expected)}`.
27564  *     This is essentially strict comparison of expected and actual.
27565  *
27566  *   - `false|undefined`: A short hand for a function which will look for a substring match in case
27567  *     insensitive way.
27568  *
27569  *     Primitive values are converted to strings. Objects are not compared against primitives,
27570  *     unless they have a custom `toString` method (e.g. `Date` objects).
27571  *
27572  * @example
27573    <example>
27574      <file name="index.html">
27575        <div ng-init="friends = [{name:'John', phone:'555-1276'},
27576                                 {name:'Mary', phone:'800-BIG-MARY'},
27577                                 {name:'Mike', phone:'555-4321'},
27578                                 {name:'Adam', phone:'555-5678'},
27579                                 {name:'Julie', phone:'555-8765'},
27580                                 {name:'Juliette', phone:'555-5678'}]"></div>
27581
27582        <label>Search: <input ng-model="searchText"></label>
27583        <table id="searchTextResults">
27584          <tr><th>Name</th><th>Phone</th></tr>
27585          <tr ng-repeat="friend in friends | filter:searchText">
27586            <td>{{friend.name}}</td>
27587            <td>{{friend.phone}}</td>
27588          </tr>
27589        </table>
27590        <hr>
27591        <label>Any: <input ng-model="search.$"></label> <br>
27592        <label>Name only <input ng-model="search.name"></label><br>
27593        <label>Phone only <input ng-model="search.phone"></label><br>
27594        <label>Equality <input type="checkbox" ng-model="strict"></label><br>
27595        <table id="searchObjResults">
27596          <tr><th>Name</th><th>Phone</th></tr>
27597          <tr ng-repeat="friendObj in friends | filter:search:strict">
27598            <td>{{friendObj.name}}</td>
27599            <td>{{friendObj.phone}}</td>
27600          </tr>
27601        </table>
27602      </file>
27603      <file name="protractor.js" type="protractor">
27604        var expectFriendNames = function(expectedNames, key) {
27605          element.all(by.repeater(key + ' in friends').column(key + '.name')).then(function(arr) {
27606            arr.forEach(function(wd, i) {
27607              expect(wd.getText()).toMatch(expectedNames[i]);
27608            });
27609          });
27610        };
27611
27612        it('should search across all fields when filtering with a string', function() {
27613          var searchText = element(by.model('searchText'));
27614          searchText.clear();
27615          searchText.sendKeys('m');
27616          expectFriendNames(['Mary', 'Mike', 'Adam'], 'friend');
27617
27618          searchText.clear();
27619          searchText.sendKeys('76');
27620          expectFriendNames(['John', 'Julie'], 'friend');
27621        });
27622
27623        it('should search in specific fields when filtering with a predicate object', function() {
27624          var searchAny = element(by.model('search.$'));
27625          searchAny.clear();
27626          searchAny.sendKeys('i');
27627          expectFriendNames(['Mary', 'Mike', 'Julie', 'Juliette'], 'friendObj');
27628        });
27629        it('should use a equal comparison when comparator is true', function() {
27630          var searchName = element(by.model('search.name'));
27631          var strict = element(by.model('strict'));
27632          searchName.clear();
27633          searchName.sendKeys('Julie');
27634          strict.click();
27635          expectFriendNames(['Julie'], 'friendObj');
27636        });
27637      </file>
27638    </example>
27639  */
27640 function filterFilter() {
27641   return function(array, expression, comparator) {
27642     if (!isArrayLike(array)) {
27643       if (array == null) {
27644         return array;
27645       } else {
27646         throw minErr('filter')('notarray', 'Expected array but received: {0}', array);
27647       }
27648     }
27649
27650     var expressionType = getTypeForFilter(expression);
27651     var predicateFn;
27652     var matchAgainstAnyProp;
27653
27654     switch (expressionType) {
27655       case 'function':
27656         predicateFn = expression;
27657         break;
27658       case 'boolean':
27659       case 'null':
27660       case 'number':
27661       case 'string':
27662         matchAgainstAnyProp = true;
27663         //jshint -W086
27664       case 'object':
27665         //jshint +W086
27666         predicateFn = createPredicateFn(expression, comparator, matchAgainstAnyProp);
27667         break;
27668       default:
27669         return array;
27670     }
27671
27672     return Array.prototype.filter.call(array, predicateFn);
27673   };
27674 }
27675
27676 // Helper functions for `filterFilter`
27677 function createPredicateFn(expression, comparator, matchAgainstAnyProp) {
27678   var shouldMatchPrimitives = isObject(expression) && ('$' in expression);
27679   var predicateFn;
27680
27681   if (comparator === true) {
27682     comparator = equals;
27683   } else if (!isFunction(comparator)) {
27684     comparator = function(actual, expected) {
27685       if (isUndefined(actual)) {
27686         // No substring matching against `undefined`
27687         return false;
27688       }
27689       if ((actual === null) || (expected === null)) {
27690         // No substring matching against `null`; only match against `null`
27691         return actual === expected;
27692       }
27693       if (isObject(expected) || (isObject(actual) && !hasCustomToString(actual))) {
27694         // Should not compare primitives against objects, unless they have custom `toString` method
27695         return false;
27696       }
27697
27698       actual = lowercase('' + actual);
27699       expected = lowercase('' + expected);
27700       return actual.indexOf(expected) !== -1;
27701     };
27702   }
27703
27704   predicateFn = function(item) {
27705     if (shouldMatchPrimitives && !isObject(item)) {
27706       return deepCompare(item, expression.$, comparator, false);
27707     }
27708     return deepCompare(item, expression, comparator, matchAgainstAnyProp);
27709   };
27710
27711   return predicateFn;
27712 }
27713
27714 function deepCompare(actual, expected, comparator, matchAgainstAnyProp, dontMatchWholeObject) {
27715   var actualType = getTypeForFilter(actual);
27716   var expectedType = getTypeForFilter(expected);
27717
27718   if ((expectedType === 'string') && (expected.charAt(0) === '!')) {
27719     return !deepCompare(actual, expected.substring(1), comparator, matchAgainstAnyProp);
27720   } else if (isArray(actual)) {
27721     // In case `actual` is an array, consider it a match
27722     // if ANY of it's items matches `expected`
27723     return actual.some(function(item) {
27724       return deepCompare(item, expected, comparator, matchAgainstAnyProp);
27725     });
27726   }
27727
27728   switch (actualType) {
27729     case 'object':
27730       var key;
27731       if (matchAgainstAnyProp) {
27732         for (key in actual) {
27733           if ((key.charAt(0) !== '$') && deepCompare(actual[key], expected, comparator, true)) {
27734             return true;
27735           }
27736         }
27737         return dontMatchWholeObject ? false : deepCompare(actual, expected, comparator, false);
27738       } else if (expectedType === 'object') {
27739         for (key in expected) {
27740           var expectedVal = expected[key];
27741           if (isFunction(expectedVal) || isUndefined(expectedVal)) {
27742             continue;
27743           }
27744
27745           var matchAnyProperty = key === '$';
27746           var actualVal = matchAnyProperty ? actual : actual[key];
27747           if (!deepCompare(actualVal, expectedVal, comparator, matchAnyProperty, matchAnyProperty)) {
27748             return false;
27749           }
27750         }
27751         return true;
27752       } else {
27753         return comparator(actual, expected);
27754       }
27755       break;
27756     case 'function':
27757       return false;
27758     default:
27759       return comparator(actual, expected);
27760   }
27761 }
27762
27763 // Used for easily differentiating between `null` and actual `object`
27764 function getTypeForFilter(val) {
27765   return (val === null) ? 'null' : typeof val;
27766 }
27767
27768 /**
27769  * @ngdoc filter
27770  * @name currency
27771  * @kind function
27772  *
27773  * @description
27774  * Formats a number as a currency (ie $1,234.56). When no currency symbol is provided, default
27775  * symbol for current locale is used.
27776  *
27777  * @param {number} amount Input to filter.
27778  * @param {string=} symbol Currency symbol or identifier to be displayed.
27779  * @param {number=} fractionSize Number of decimal places to round the amount to, defaults to default max fraction size for current locale
27780  * @returns {string} Formatted number.
27781  *
27782  *
27783  * @example
27784    <example module="currencyExample">
27785      <file name="index.html">
27786        <script>
27787          angular.module('currencyExample', [])
27788            .controller('ExampleController', ['$scope', function($scope) {
27789              $scope.amount = 1234.56;
27790            }]);
27791        </script>
27792        <div ng-controller="ExampleController">
27793          <input type="number" ng-model="amount" aria-label="amount"> <br>
27794          default currency symbol ($): <span id="currency-default">{{amount | currency}}</span><br>
27795          custom currency identifier (USD$): <span id="currency-custom">{{amount | currency:"USD$"}}</span>
27796          no fractions (0): <span id="currency-no-fractions">{{amount | currency:"USD$":0}}</span>
27797        </div>
27798      </file>
27799      <file name="protractor.js" type="protractor">
27800        it('should init with 1234.56', function() {
27801          expect(element(by.id('currency-default')).getText()).toBe('$1,234.56');
27802          expect(element(by.id('currency-custom')).getText()).toBe('USD$1,234.56');
27803          expect(element(by.id('currency-no-fractions')).getText()).toBe('USD$1,235');
27804        });
27805        it('should update', function() {
27806          if (browser.params.browser == 'safari') {
27807            // Safari does not understand the minus key. See
27808            // https://github.com/angular/protractor/issues/481
27809            return;
27810          }
27811          element(by.model('amount')).clear();
27812          element(by.model('amount')).sendKeys('-1234');
27813          expect(element(by.id('currency-default')).getText()).toBe('-$1,234.00');
27814          expect(element(by.id('currency-custom')).getText()).toBe('-USD$1,234.00');
27815          expect(element(by.id('currency-no-fractions')).getText()).toBe('-USD$1,234');
27816        });
27817      </file>
27818    </example>
27819  */
27820 currencyFilter.$inject = ['$locale'];
27821 function currencyFilter($locale) {
27822   var formats = $locale.NUMBER_FORMATS;
27823   return function(amount, currencySymbol, fractionSize) {
27824     if (isUndefined(currencySymbol)) {
27825       currencySymbol = formats.CURRENCY_SYM;
27826     }
27827
27828     if (isUndefined(fractionSize)) {
27829       fractionSize = formats.PATTERNS[1].maxFrac;
27830     }
27831
27832     // if null or undefined pass it through
27833     return (amount == null)
27834         ? amount
27835         : formatNumber(amount, formats.PATTERNS[1], formats.GROUP_SEP, formats.DECIMAL_SEP, fractionSize).
27836             replace(/\u00A4/g, currencySymbol);
27837   };
27838 }
27839
27840 /**
27841  * @ngdoc filter
27842  * @name number
27843  * @kind function
27844  *
27845  * @description
27846  * Formats a number as text.
27847  *
27848  * If the input is null or undefined, it will just be returned.
27849  * If the input is infinite (Infinity/-Infinity) the Infinity symbol '∞' is returned.
27850  * If the input is not a number an empty string is returned.
27851  *
27852  *
27853  * @param {number|string} number Number to format.
27854  * @param {(number|string)=} fractionSize Number of decimal places to round the number to.
27855  * If this is not provided then the fraction size is computed from the current locale's number
27856  * formatting pattern. In the case of the default locale, it will be 3.
27857  * @returns {string} Number rounded to decimalPlaces and places a “,” after each third digit.
27858  *
27859  * @example
27860    <example module="numberFilterExample">
27861      <file name="index.html">
27862        <script>
27863          angular.module('numberFilterExample', [])
27864            .controller('ExampleController', ['$scope', function($scope) {
27865              $scope.val = 1234.56789;
27866            }]);
27867        </script>
27868        <div ng-controller="ExampleController">
27869          <label>Enter number: <input ng-model='val'></label><br>
27870          Default formatting: <span id='number-default'>{{val | number}}</span><br>
27871          No fractions: <span>{{val | number:0}}</span><br>
27872          Negative number: <span>{{-val | number:4}}</span>
27873        </div>
27874      </file>
27875      <file name="protractor.js" type="protractor">
27876        it('should format numbers', function() {
27877          expect(element(by.id('number-default')).getText()).toBe('1,234.568');
27878          expect(element(by.binding('val | number:0')).getText()).toBe('1,235');
27879          expect(element(by.binding('-val | number:4')).getText()).toBe('-1,234.5679');
27880        });
27881
27882        it('should update', function() {
27883          element(by.model('val')).clear();
27884          element(by.model('val')).sendKeys('3374.333');
27885          expect(element(by.id('number-default')).getText()).toBe('3,374.333');
27886          expect(element(by.binding('val | number:0')).getText()).toBe('3,374');
27887          expect(element(by.binding('-val | number:4')).getText()).toBe('-3,374.3330');
27888       });
27889      </file>
27890    </example>
27891  */
27892
27893
27894 numberFilter.$inject = ['$locale'];
27895 function numberFilter($locale) {
27896   var formats = $locale.NUMBER_FORMATS;
27897   return function(number, fractionSize) {
27898
27899     // if null or undefined pass it through
27900     return (number == null)
27901         ? number
27902         : formatNumber(number, formats.PATTERNS[0], formats.GROUP_SEP, formats.DECIMAL_SEP,
27903                        fractionSize);
27904   };
27905 }
27906
27907 var DECIMAL_SEP = '.';
27908 function formatNumber(number, pattern, groupSep, decimalSep, fractionSize) {
27909   if (isObject(number)) return '';
27910
27911   var isNegative = number < 0;
27912   number = Math.abs(number);
27913
27914   var isInfinity = number === Infinity;
27915   if (!isInfinity && !isFinite(number)) return '';
27916
27917   var numStr = number + '',
27918       formatedText = '',
27919       hasExponent = false,
27920       parts = [];
27921
27922   if (isInfinity) formatedText = '\u221e';
27923
27924   if (!isInfinity && numStr.indexOf('e') !== -1) {
27925     var match = numStr.match(/([\d\.]+)e(-?)(\d+)/);
27926     if (match && match[2] == '-' && match[3] > fractionSize + 1) {
27927       number = 0;
27928     } else {
27929       formatedText = numStr;
27930       hasExponent = true;
27931     }
27932   }
27933
27934   if (!isInfinity && !hasExponent) {
27935     var fractionLen = (numStr.split(DECIMAL_SEP)[1] || '').length;
27936
27937     // determine fractionSize if it is not specified
27938     if (isUndefined(fractionSize)) {
27939       fractionSize = Math.min(Math.max(pattern.minFrac, fractionLen), pattern.maxFrac);
27940     }
27941
27942     // safely round numbers in JS without hitting imprecisions of floating-point arithmetics
27943     // inspired by:
27944     // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/round
27945     number = +(Math.round(+(number.toString() + 'e' + fractionSize)).toString() + 'e' + -fractionSize);
27946
27947     var fraction = ('' + number).split(DECIMAL_SEP);
27948     var whole = fraction[0];
27949     fraction = fraction[1] || '';
27950
27951     var i, pos = 0,
27952         lgroup = pattern.lgSize,
27953         group = pattern.gSize;
27954
27955     if (whole.length >= (lgroup + group)) {
27956       pos = whole.length - lgroup;
27957       for (i = 0; i < pos; i++) {
27958         if ((pos - i) % group === 0 && i !== 0) {
27959           formatedText += groupSep;
27960         }
27961         formatedText += whole.charAt(i);
27962       }
27963     }
27964
27965     for (i = pos; i < whole.length; i++) {
27966       if ((whole.length - i) % lgroup === 0 && i !== 0) {
27967         formatedText += groupSep;
27968       }
27969       formatedText += whole.charAt(i);
27970     }
27971
27972     // format fraction part.
27973     while (fraction.length < fractionSize) {
27974       fraction += '0';
27975     }
27976
27977     if (fractionSize && fractionSize !== "0") formatedText += decimalSep + fraction.substr(0, fractionSize);
27978   } else {
27979     if (fractionSize > 0 && number < 1) {
27980       formatedText = number.toFixed(fractionSize);
27981       number = parseFloat(formatedText);
27982       formatedText = formatedText.replace(DECIMAL_SEP, decimalSep);
27983     }
27984   }
27985
27986   if (number === 0) {
27987     isNegative = false;
27988   }
27989
27990   parts.push(isNegative ? pattern.negPre : pattern.posPre,
27991              formatedText,
27992              isNegative ? pattern.negSuf : pattern.posSuf);
27993   return parts.join('');
27994 }
27995
27996 function padNumber(num, digits, trim) {
27997   var neg = '';
27998   if (num < 0) {
27999     neg =  '-';
28000     num = -num;
28001   }
28002   num = '' + num;
28003   while (num.length < digits) num = '0' + num;
28004   if (trim) {
28005     num = num.substr(num.length - digits);
28006   }
28007   return neg + num;
28008 }
28009
28010
28011 function dateGetter(name, size, offset, trim) {
28012   offset = offset || 0;
28013   return function(date) {
28014     var value = date['get' + name]();
28015     if (offset > 0 || value > -offset) {
28016       value += offset;
28017     }
28018     if (value === 0 && offset == -12) value = 12;
28019     return padNumber(value, size, trim);
28020   };
28021 }
28022
28023 function dateStrGetter(name, shortForm) {
28024   return function(date, formats) {
28025     var value = date['get' + name]();
28026     var get = uppercase(shortForm ? ('SHORT' + name) : name);
28027
28028     return formats[get][value];
28029   };
28030 }
28031
28032 function timeZoneGetter(date, formats, offset) {
28033   var zone = -1 * offset;
28034   var paddedZone = (zone >= 0) ? "+" : "";
28035
28036   paddedZone += padNumber(Math[zone > 0 ? 'floor' : 'ceil'](zone / 60), 2) +
28037                 padNumber(Math.abs(zone % 60), 2);
28038
28039   return paddedZone;
28040 }
28041
28042 function getFirstThursdayOfYear(year) {
28043     // 0 = index of January
28044     var dayOfWeekOnFirst = (new Date(year, 0, 1)).getDay();
28045     // 4 = index of Thursday (+1 to account for 1st = 5)
28046     // 11 = index of *next* Thursday (+1 account for 1st = 12)
28047     return new Date(year, 0, ((dayOfWeekOnFirst <= 4) ? 5 : 12) - dayOfWeekOnFirst);
28048 }
28049
28050 function getThursdayThisWeek(datetime) {
28051     return new Date(datetime.getFullYear(), datetime.getMonth(),
28052       // 4 = index of Thursday
28053       datetime.getDate() + (4 - datetime.getDay()));
28054 }
28055
28056 function weekGetter(size) {
28057    return function(date) {
28058       var firstThurs = getFirstThursdayOfYear(date.getFullYear()),
28059          thisThurs = getThursdayThisWeek(date);
28060
28061       var diff = +thisThurs - +firstThurs,
28062          result = 1 + Math.round(diff / 6.048e8); // 6.048e8 ms per week
28063
28064       return padNumber(result, size);
28065    };
28066 }
28067
28068 function ampmGetter(date, formats) {
28069   return date.getHours() < 12 ? formats.AMPMS[0] : formats.AMPMS[1];
28070 }
28071
28072 function eraGetter(date, formats) {
28073   return date.getFullYear() <= 0 ? formats.ERAS[0] : formats.ERAS[1];
28074 }
28075
28076 function longEraGetter(date, formats) {
28077   return date.getFullYear() <= 0 ? formats.ERANAMES[0] : formats.ERANAMES[1];
28078 }
28079
28080 var DATE_FORMATS = {
28081   yyyy: dateGetter('FullYear', 4),
28082     yy: dateGetter('FullYear', 2, 0, true),
28083      y: dateGetter('FullYear', 1),
28084   MMMM: dateStrGetter('Month'),
28085    MMM: dateStrGetter('Month', true),
28086     MM: dateGetter('Month', 2, 1),
28087      M: dateGetter('Month', 1, 1),
28088     dd: dateGetter('Date', 2),
28089      d: dateGetter('Date', 1),
28090     HH: dateGetter('Hours', 2),
28091      H: dateGetter('Hours', 1),
28092     hh: dateGetter('Hours', 2, -12),
28093      h: dateGetter('Hours', 1, -12),
28094     mm: dateGetter('Minutes', 2),
28095      m: dateGetter('Minutes', 1),
28096     ss: dateGetter('Seconds', 2),
28097      s: dateGetter('Seconds', 1),
28098      // while ISO 8601 requires fractions to be prefixed with `.` or `,`
28099      // we can be just safely rely on using `sss` since we currently don't support single or two digit fractions
28100    sss: dateGetter('Milliseconds', 3),
28101   EEEE: dateStrGetter('Day'),
28102    EEE: dateStrGetter('Day', true),
28103      a: ampmGetter,
28104      Z: timeZoneGetter,
28105     ww: weekGetter(2),
28106      w: weekGetter(1),
28107      G: eraGetter,
28108      GG: eraGetter,
28109      GGG: eraGetter,
28110      GGGG: longEraGetter
28111 };
28112
28113 var DATE_FORMATS_SPLIT = /((?:[^yMdHhmsaZEwG']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|d+|H+|h+|m+|s+|a|Z|G+|w+))(.*)/,
28114     NUMBER_STRING = /^\-?\d+$/;
28115
28116 /**
28117  * @ngdoc filter
28118  * @name date
28119  * @kind function
28120  *
28121  * @description
28122  *   Formats `date` to a string based on the requested `format`.
28123  *
28124  *   `format` string can be composed of the following elements:
28125  *
28126  *   * `'yyyy'`: 4 digit representation of year (e.g. AD 1 => 0001, AD 2010 => 2010)
28127  *   * `'yy'`: 2 digit representation of year, padded (00-99). (e.g. AD 2001 => 01, AD 2010 => 10)
28128  *   * `'y'`: 1 digit representation of year, e.g. (AD 1 => 1, AD 199 => 199)
28129  *   * `'MMMM'`: Month in year (January-December)
28130  *   * `'MMM'`: Month in year (Jan-Dec)
28131  *   * `'MM'`: Month in year, padded (01-12)
28132  *   * `'M'`: Month in year (1-12)
28133  *   * `'dd'`: Day in month, padded (01-31)
28134  *   * `'d'`: Day in month (1-31)
28135  *   * `'EEEE'`: Day in Week,(Sunday-Saturday)
28136  *   * `'EEE'`: Day in Week, (Sun-Sat)
28137  *   * `'HH'`: Hour in day, padded (00-23)
28138  *   * `'H'`: Hour in day (0-23)
28139  *   * `'hh'`: Hour in AM/PM, padded (01-12)
28140  *   * `'h'`: Hour in AM/PM, (1-12)
28141  *   * `'mm'`: Minute in hour, padded (00-59)
28142  *   * `'m'`: Minute in hour (0-59)
28143  *   * `'ss'`: Second in minute, padded (00-59)
28144  *   * `'s'`: Second in minute (0-59)
28145  *   * `'sss'`: Millisecond in second, padded (000-999)
28146  *   * `'a'`: AM/PM marker
28147  *   * `'Z'`: 4 digit (+sign) representation of the timezone offset (-1200-+1200)
28148  *   * `'ww'`: Week of year, padded (00-53). Week 01 is the week with the first Thursday of the year
28149  *   * `'w'`: Week of year (0-53). Week 1 is the week with the first Thursday of the year
28150  *   * `'G'`, `'GG'`, `'GGG'`: The abbreviated form of the era string (e.g. 'AD')
28151  *   * `'GGGG'`: The long form of the era string (e.g. 'Anno Domini')
28152  *
28153  *   `format` string can also be one of the following predefined
28154  *   {@link guide/i18n localizable formats}:
28155  *
28156  *   * `'medium'`: equivalent to `'MMM d, y h:mm:ss a'` for en_US locale
28157  *     (e.g. Sep 3, 2010 12:05:08 PM)
28158  *   * `'short'`: equivalent to `'M/d/yy h:mm a'` for en_US  locale (e.g. 9/3/10 12:05 PM)
28159  *   * `'fullDate'`: equivalent to `'EEEE, MMMM d, y'` for en_US  locale
28160  *     (e.g. Friday, September 3, 2010)
28161  *   * `'longDate'`: equivalent to `'MMMM d, y'` for en_US  locale (e.g. September 3, 2010)
28162  *   * `'mediumDate'`: equivalent to `'MMM d, y'` for en_US  locale (e.g. Sep 3, 2010)
28163  *   * `'shortDate'`: equivalent to `'M/d/yy'` for en_US locale (e.g. 9/3/10)
28164  *   * `'mediumTime'`: equivalent to `'h:mm:ss a'` for en_US locale (e.g. 12:05:08 PM)
28165  *   * `'shortTime'`: equivalent to `'h:mm a'` for en_US locale (e.g. 12:05 PM)
28166  *
28167  *   `format` string can contain literal values. These need to be escaped by surrounding with single quotes (e.g.
28168  *   `"h 'in the morning'"`). In order to output a single quote, escape it - i.e., two single quotes in a sequence
28169  *   (e.g. `"h 'o''clock'"`).
28170  *
28171  * @param {(Date|number|string)} date Date to format either as Date object, milliseconds (string or
28172  *    number) or various ISO 8601 datetime string formats (e.g. yyyy-MM-ddTHH:mm:ss.sssZ and its
28173  *    shorter versions like yyyy-MM-ddTHH:mmZ, yyyy-MM-dd or yyyyMMddTHHmmssZ). If no timezone is
28174  *    specified in the string input, the time is considered to be in the local timezone.
28175  * @param {string=} format Formatting rules (see Description). If not specified,
28176  *    `mediumDate` is used.
28177  * @param {string=} timezone Timezone to be used for formatting. It understands UTC/GMT and the
28178  *    continental US time zone abbreviations, but for general use, use a time zone offset, for
28179  *    example, `'+0430'` (4 hours, 30 minutes east of the Greenwich meridian)
28180  *    If not specified, the timezone of the browser will be used.
28181  * @returns {string} Formatted string or the input if input is not recognized as date/millis.
28182  *
28183  * @example
28184    <example>
28185      <file name="index.html">
28186        <span ng-non-bindable>{{1288323623006 | date:'medium'}}</span>:
28187            <span>{{1288323623006 | date:'medium'}}</span><br>
28188        <span ng-non-bindable>{{1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'}}</span>:
28189           <span>{{1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'}}</span><br>
28190        <span ng-non-bindable>{{1288323623006 | date:'MM/dd/yyyy @ h:mma'}}</span>:
28191           <span>{{'1288323623006' | date:'MM/dd/yyyy @ h:mma'}}</span><br>
28192        <span ng-non-bindable>{{1288323623006 | date:"MM/dd/yyyy 'at' h:mma"}}</span>:
28193           <span>{{'1288323623006' | date:"MM/dd/yyyy 'at' h:mma"}}</span><br>
28194      </file>
28195      <file name="protractor.js" type="protractor">
28196        it('should format date', function() {
28197          expect(element(by.binding("1288323623006 | date:'medium'")).getText()).
28198             toMatch(/Oct 2\d, 2010 \d{1,2}:\d{2}:\d{2} (AM|PM)/);
28199          expect(element(by.binding("1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'")).getText()).
28200             toMatch(/2010\-10\-2\d \d{2}:\d{2}:\d{2} (\-|\+)?\d{4}/);
28201          expect(element(by.binding("'1288323623006' | date:'MM/dd/yyyy @ h:mma'")).getText()).
28202             toMatch(/10\/2\d\/2010 @ \d{1,2}:\d{2}(AM|PM)/);
28203          expect(element(by.binding("'1288323623006' | date:\"MM/dd/yyyy 'at' h:mma\"")).getText()).
28204             toMatch(/10\/2\d\/2010 at \d{1,2}:\d{2}(AM|PM)/);
28205        });
28206      </file>
28207    </example>
28208  */
28209 dateFilter.$inject = ['$locale'];
28210 function dateFilter($locale) {
28211
28212
28213   var R_ISO8601_STR = /^(\d{4})-?(\d\d)-?(\d\d)(?:T(\d\d)(?::?(\d\d)(?::?(\d\d)(?:\.(\d+))?)?)?(Z|([+-])(\d\d):?(\d\d))?)?$/;
28214                      // 1        2       3         4          5          6          7          8  9     10      11
28215   function jsonStringToDate(string) {
28216     var match;
28217     if (match = string.match(R_ISO8601_STR)) {
28218       var date = new Date(0),
28219           tzHour = 0,
28220           tzMin  = 0,
28221           dateSetter = match[8] ? date.setUTCFullYear : date.setFullYear,
28222           timeSetter = match[8] ? date.setUTCHours : date.setHours;
28223
28224       if (match[9]) {
28225         tzHour = toInt(match[9] + match[10]);
28226         tzMin = toInt(match[9] + match[11]);
28227       }
28228       dateSetter.call(date, toInt(match[1]), toInt(match[2]) - 1, toInt(match[3]));
28229       var h = toInt(match[4] || 0) - tzHour;
28230       var m = toInt(match[5] || 0) - tzMin;
28231       var s = toInt(match[6] || 0);
28232       var ms = Math.round(parseFloat('0.' + (match[7] || 0)) * 1000);
28233       timeSetter.call(date, h, m, s, ms);
28234       return date;
28235     }
28236     return string;
28237   }
28238
28239
28240   return function(date, format, timezone) {
28241     var text = '',
28242         parts = [],
28243         fn, match;
28244
28245     format = format || 'mediumDate';
28246     format = $locale.DATETIME_FORMATS[format] || format;
28247     if (isString(date)) {
28248       date = NUMBER_STRING.test(date) ? toInt(date) : jsonStringToDate(date);
28249     }
28250
28251     if (isNumber(date)) {
28252       date = new Date(date);
28253     }
28254
28255     if (!isDate(date) || !isFinite(date.getTime())) {
28256       return date;
28257     }
28258
28259     while (format) {
28260       match = DATE_FORMATS_SPLIT.exec(format);
28261       if (match) {
28262         parts = concat(parts, match, 1);
28263         format = parts.pop();
28264       } else {
28265         parts.push(format);
28266         format = null;
28267       }
28268     }
28269
28270     var dateTimezoneOffset = date.getTimezoneOffset();
28271     if (timezone) {
28272       dateTimezoneOffset = timezoneToOffset(timezone, date.getTimezoneOffset());
28273       date = convertTimezoneToLocal(date, timezone, true);
28274     }
28275     forEach(parts, function(value) {
28276       fn = DATE_FORMATS[value];
28277       text += fn ? fn(date, $locale.DATETIME_FORMATS, dateTimezoneOffset)
28278                  : value.replace(/(^'|'$)/g, '').replace(/''/g, "'");
28279     });
28280
28281     return text;
28282   };
28283 }
28284
28285
28286 /**
28287  * @ngdoc filter
28288  * @name json
28289  * @kind function
28290  *
28291  * @description
28292  *   Allows you to convert a JavaScript object into JSON string.
28293  *
28294  *   This filter is mostly useful for debugging. When using the double curly {{value}} notation
28295  *   the binding is automatically converted to JSON.
28296  *
28297  * @param {*} object Any JavaScript object (including arrays and primitive types) to filter.
28298  * @param {number=} spacing The number of spaces to use per indentation, defaults to 2.
28299  * @returns {string} JSON string.
28300  *
28301  *
28302  * @example
28303    <example>
28304      <file name="index.html">
28305        <pre id="default-spacing">{{ {'name':'value'} | json }}</pre>
28306        <pre id="custom-spacing">{{ {'name':'value'} | json:4 }}</pre>
28307      </file>
28308      <file name="protractor.js" type="protractor">
28309        it('should jsonify filtered objects', function() {
28310          expect(element(by.id('default-spacing')).getText()).toMatch(/\{\n  "name": ?"value"\n}/);
28311          expect(element(by.id('custom-spacing')).getText()).toMatch(/\{\n    "name": ?"value"\n}/);
28312        });
28313      </file>
28314    </example>
28315  *
28316  */
28317 function jsonFilter() {
28318   return function(object, spacing) {
28319     if (isUndefined(spacing)) {
28320         spacing = 2;
28321     }
28322     return toJson(object, spacing);
28323   };
28324 }
28325
28326
28327 /**
28328  * @ngdoc filter
28329  * @name lowercase
28330  * @kind function
28331  * @description
28332  * Converts string to lowercase.
28333  * @see angular.lowercase
28334  */
28335 var lowercaseFilter = valueFn(lowercase);
28336
28337
28338 /**
28339  * @ngdoc filter
28340  * @name uppercase
28341  * @kind function
28342  * @description
28343  * Converts string to uppercase.
28344  * @see angular.uppercase
28345  */
28346 var uppercaseFilter = valueFn(uppercase);
28347
28348 /**
28349  * @ngdoc filter
28350  * @name limitTo
28351  * @kind function
28352  *
28353  * @description
28354  * Creates a new array or string containing only a specified number of elements. The elements
28355  * are taken from either the beginning or the end of the source array, string or number, as specified by
28356  * the value and sign (positive or negative) of `limit`. If a number is used as input, it is
28357  * converted to a string.
28358  *
28359  * @param {Array|string|number} input Source array, string or number to be limited.
28360  * @param {string|number} limit The length of the returned array or string. If the `limit` number
28361  *     is positive, `limit` number of items from the beginning of the source array/string are copied.
28362  *     If the number is negative, `limit` number  of items from the end of the source array/string
28363  *     are copied. The `limit` will be trimmed if it exceeds `array.length`. If `limit` is undefined,
28364  *     the input will be returned unchanged.
28365  * @param {(string|number)=} begin Index at which to begin limitation. As a negative index, `begin`
28366  *     indicates an offset from the end of `input`. Defaults to `0`.
28367  * @returns {Array|string} A new sub-array or substring of length `limit` or less if input array
28368  *     had less than `limit` elements.
28369  *
28370  * @example
28371    <example module="limitToExample">
28372      <file name="index.html">
28373        <script>
28374          angular.module('limitToExample', [])
28375            .controller('ExampleController', ['$scope', function($scope) {
28376              $scope.numbers = [1,2,3,4,5,6,7,8,9];
28377              $scope.letters = "abcdefghi";
28378              $scope.longNumber = 2345432342;
28379              $scope.numLimit = 3;
28380              $scope.letterLimit = 3;
28381              $scope.longNumberLimit = 3;
28382            }]);
28383        </script>
28384        <div ng-controller="ExampleController">
28385          <label>
28386             Limit {{numbers}} to:
28387             <input type="number" step="1" ng-model="numLimit">
28388          </label>
28389          <p>Output numbers: {{ numbers | limitTo:numLimit }}</p>
28390          <label>
28391             Limit {{letters}} to:
28392             <input type="number" step="1" ng-model="letterLimit">
28393          </label>
28394          <p>Output letters: {{ letters | limitTo:letterLimit }}</p>
28395          <label>
28396             Limit {{longNumber}} to:
28397             <input type="number" step="1" ng-model="longNumberLimit">
28398          </label>
28399          <p>Output long number: {{ longNumber | limitTo:longNumberLimit }}</p>
28400        </div>
28401      </file>
28402      <file name="protractor.js" type="protractor">
28403        var numLimitInput = element(by.model('numLimit'));
28404        var letterLimitInput = element(by.model('letterLimit'));
28405        var longNumberLimitInput = element(by.model('longNumberLimit'));
28406        var limitedNumbers = element(by.binding('numbers | limitTo:numLimit'));
28407        var limitedLetters = element(by.binding('letters | limitTo:letterLimit'));
28408        var limitedLongNumber = element(by.binding('longNumber | limitTo:longNumberLimit'));
28409
28410        it('should limit the number array to first three items', function() {
28411          expect(numLimitInput.getAttribute('value')).toBe('3');
28412          expect(letterLimitInput.getAttribute('value')).toBe('3');
28413          expect(longNumberLimitInput.getAttribute('value')).toBe('3');
28414          expect(limitedNumbers.getText()).toEqual('Output numbers: [1,2,3]');
28415          expect(limitedLetters.getText()).toEqual('Output letters: abc');
28416          expect(limitedLongNumber.getText()).toEqual('Output long number: 234');
28417        });
28418
28419        // There is a bug in safari and protractor that doesn't like the minus key
28420        // it('should update the output when -3 is entered', function() {
28421        //   numLimitInput.clear();
28422        //   numLimitInput.sendKeys('-3');
28423        //   letterLimitInput.clear();
28424        //   letterLimitInput.sendKeys('-3');
28425        //   longNumberLimitInput.clear();
28426        //   longNumberLimitInput.sendKeys('-3');
28427        //   expect(limitedNumbers.getText()).toEqual('Output numbers: [7,8,9]');
28428        //   expect(limitedLetters.getText()).toEqual('Output letters: ghi');
28429        //   expect(limitedLongNumber.getText()).toEqual('Output long number: 342');
28430        // });
28431
28432        it('should not exceed the maximum size of input array', function() {
28433          numLimitInput.clear();
28434          numLimitInput.sendKeys('100');
28435          letterLimitInput.clear();
28436          letterLimitInput.sendKeys('100');
28437          longNumberLimitInput.clear();
28438          longNumberLimitInput.sendKeys('100');
28439          expect(limitedNumbers.getText()).toEqual('Output numbers: [1,2,3,4,5,6,7,8,9]');
28440          expect(limitedLetters.getText()).toEqual('Output letters: abcdefghi');
28441          expect(limitedLongNumber.getText()).toEqual('Output long number: 2345432342');
28442        });
28443      </file>
28444    </example>
28445 */
28446 function limitToFilter() {
28447   return function(input, limit, begin) {
28448     if (Math.abs(Number(limit)) === Infinity) {
28449       limit = Number(limit);
28450     } else {
28451       limit = toInt(limit);
28452     }
28453     if (isNaN(limit)) return input;
28454
28455     if (isNumber(input)) input = input.toString();
28456     if (!isArray(input) && !isString(input)) return input;
28457
28458     begin = (!begin || isNaN(begin)) ? 0 : toInt(begin);
28459     begin = (begin < 0) ? Math.max(0, input.length + begin) : begin;
28460
28461     if (limit >= 0) {
28462       return input.slice(begin, begin + limit);
28463     } else {
28464       if (begin === 0) {
28465         return input.slice(limit, input.length);
28466       } else {
28467         return input.slice(Math.max(0, begin + limit), begin);
28468       }
28469     }
28470   };
28471 }
28472
28473 /**
28474  * @ngdoc filter
28475  * @name orderBy
28476  * @kind function
28477  *
28478  * @description
28479  * Orders a specified `array` by the `expression` predicate. It is ordered alphabetically
28480  * for strings and numerically for numbers. Note: if you notice numbers are not being sorted
28481  * as expected, make sure they are actually being saved as numbers and not strings.
28482  *
28483  * @param {Array} array The array to sort.
28484  * @param {function(*)|string|Array.<(function(*)|string)>=} expression A predicate to be
28485  *    used by the comparator to determine the order of elements.
28486  *
28487  *    Can be one of:
28488  *
28489  *    - `function`: Getter function. The result of this function will be sorted using the
28490  *      `<`, `===`, `>` operator.
28491  *    - `string`: An Angular expression. The result of this expression is used to compare elements
28492  *      (for example `name` to sort by a property called `name` or `name.substr(0, 3)` to sort by
28493  *      3 first characters of a property called `name`). The result of a constant expression
28494  *      is interpreted as a property name to be used in comparisons (for example `"special name"`
28495  *      to sort object by the value of their `special name` property). An expression can be
28496  *      optionally prefixed with `+` or `-` to control ascending or descending sort order
28497  *      (for example, `+name` or `-name`). If no property is provided, (e.g. `'+'`) then the array
28498  *      element itself is used to compare where sorting.
28499  *    - `Array`: An array of function or string predicates. The first predicate in the array
28500  *      is used for sorting, but when two items are equivalent, the next predicate is used.
28501  *
28502  *    If the predicate is missing or empty then it defaults to `'+'`.
28503  *
28504  * @param {boolean=} reverse Reverse the order of the array.
28505  * @returns {Array} Sorted copy of the source array.
28506  *
28507  *
28508  * @example
28509  * The example below demonstrates a simple ngRepeat, where the data is sorted
28510  * by age in descending order (predicate is set to `'-age'`).
28511  * `reverse` is not set, which means it defaults to `false`.
28512    <example module="orderByExample">
28513      <file name="index.html">
28514        <script>
28515          angular.module('orderByExample', [])
28516            .controller('ExampleController', ['$scope', function($scope) {
28517              $scope.friends =
28518                  [{name:'John', phone:'555-1212', age:10},
28519                   {name:'Mary', phone:'555-9876', age:19},
28520                   {name:'Mike', phone:'555-4321', age:21},
28521                   {name:'Adam', phone:'555-5678', age:35},
28522                   {name:'Julie', phone:'555-8765', age:29}];
28523            }]);
28524        </script>
28525        <div ng-controller="ExampleController">
28526          <table class="friend">
28527            <tr>
28528              <th>Name</th>
28529              <th>Phone Number</th>
28530              <th>Age</th>
28531            </tr>
28532            <tr ng-repeat="friend in friends | orderBy:'-age'">
28533              <td>{{friend.name}}</td>
28534              <td>{{friend.phone}}</td>
28535              <td>{{friend.age}}</td>
28536            </tr>
28537          </table>
28538        </div>
28539      </file>
28540    </example>
28541  *
28542  * The predicate and reverse parameters can be controlled dynamically through scope properties,
28543  * as shown in the next example.
28544  * @example
28545    <example module="orderByExample">
28546      <file name="index.html">
28547        <script>
28548          angular.module('orderByExample', [])
28549            .controller('ExampleController', ['$scope', function($scope) {
28550              $scope.friends =
28551                  [{name:'John', phone:'555-1212', age:10},
28552                   {name:'Mary', phone:'555-9876', age:19},
28553                   {name:'Mike', phone:'555-4321', age:21},
28554                   {name:'Adam', phone:'555-5678', age:35},
28555                   {name:'Julie', phone:'555-8765', age:29}];
28556              $scope.predicate = 'age';
28557              $scope.reverse = true;
28558              $scope.order = function(predicate) {
28559                $scope.reverse = ($scope.predicate === predicate) ? !$scope.reverse : false;
28560                $scope.predicate = predicate;
28561              };
28562            }]);
28563        </script>
28564        <style type="text/css">
28565          .sortorder:after {
28566            content: '\25b2';
28567          }
28568          .sortorder.reverse:after {
28569            content: '\25bc';
28570          }
28571        </style>
28572        <div ng-controller="ExampleController">
28573          <pre>Sorting predicate = {{predicate}}; reverse = {{reverse}}</pre>
28574          <hr/>
28575          [ <a href="" ng-click="predicate=''">unsorted</a> ]
28576          <table class="friend">
28577            <tr>
28578              <th>
28579                <a href="" ng-click="order('name')">Name</a>
28580                <span class="sortorder" ng-show="predicate === 'name'" ng-class="{reverse:reverse}"></span>
28581              </th>
28582              <th>
28583                <a href="" ng-click="order('phone')">Phone Number</a>
28584                <span class="sortorder" ng-show="predicate === 'phone'" ng-class="{reverse:reverse}"></span>
28585              </th>
28586              <th>
28587                <a href="" ng-click="order('age')">Age</a>
28588                <span class="sortorder" ng-show="predicate === 'age'" ng-class="{reverse:reverse}"></span>
28589              </th>
28590            </tr>
28591            <tr ng-repeat="friend in friends | orderBy:predicate:reverse">
28592              <td>{{friend.name}}</td>
28593              <td>{{friend.phone}}</td>
28594              <td>{{friend.age}}</td>
28595            </tr>
28596          </table>
28597        </div>
28598      </file>
28599    </example>
28600  *
28601  * It's also possible to call the orderBy filter manually, by injecting `$filter`, retrieving the
28602  * filter routine with `$filter('orderBy')`, and calling the returned filter routine with the
28603  * desired parameters.
28604  *
28605  * Example:
28606  *
28607  * @example
28608   <example module="orderByExample">
28609     <file name="index.html">
28610       <div ng-controller="ExampleController">
28611         <table class="friend">
28612           <tr>
28613             <th><a href="" ng-click="reverse=false;order('name', false)">Name</a>
28614               (<a href="" ng-click="order('-name',false)">^</a>)</th>
28615             <th><a href="" ng-click="reverse=!reverse;order('phone', reverse)">Phone Number</a></th>
28616             <th><a href="" ng-click="reverse=!reverse;order('age',reverse)">Age</a></th>
28617           </tr>
28618           <tr ng-repeat="friend in friends">
28619             <td>{{friend.name}}</td>
28620             <td>{{friend.phone}}</td>
28621             <td>{{friend.age}}</td>
28622           </tr>
28623         </table>
28624       </div>
28625     </file>
28626
28627     <file name="script.js">
28628       angular.module('orderByExample', [])
28629         .controller('ExampleController', ['$scope', '$filter', function($scope, $filter) {
28630           var orderBy = $filter('orderBy');
28631           $scope.friends = [
28632             { name: 'John',    phone: '555-1212',    age: 10 },
28633             { name: 'Mary',    phone: '555-9876',    age: 19 },
28634             { name: 'Mike',    phone: '555-4321',    age: 21 },
28635             { name: 'Adam',    phone: '555-5678',    age: 35 },
28636             { name: 'Julie',   phone: '555-8765',    age: 29 }
28637           ];
28638           $scope.order = function(predicate, reverse) {
28639             $scope.friends = orderBy($scope.friends, predicate, reverse);
28640           };
28641           $scope.order('-age',false);
28642         }]);
28643     </file>
28644 </example>
28645  */
28646 orderByFilter.$inject = ['$parse'];
28647 function orderByFilter($parse) {
28648   return function(array, sortPredicate, reverseOrder) {
28649
28650     if (!(isArrayLike(array))) return array;
28651
28652     if (!isArray(sortPredicate)) { sortPredicate = [sortPredicate]; }
28653     if (sortPredicate.length === 0) { sortPredicate = ['+']; }
28654
28655     var predicates = processPredicates(sortPredicate, reverseOrder);
28656     // Add a predicate at the end that evaluates to the element index. This makes the
28657     // sort stable as it works as a tie-breaker when all the input predicates cannot
28658     // distinguish between two elements.
28659     predicates.push({ get: function() { return {}; }, descending: reverseOrder ? -1 : 1});
28660
28661     // The next three lines are a version of a Swartzian Transform idiom from Perl
28662     // (sometimes called the Decorate-Sort-Undecorate idiom)
28663     // See https://en.wikipedia.org/wiki/Schwartzian_transform
28664     var compareValues = Array.prototype.map.call(array, getComparisonObject);
28665     compareValues.sort(doComparison);
28666     array = compareValues.map(function(item) { return item.value; });
28667
28668     return array;
28669
28670     function getComparisonObject(value, index) {
28671       return {
28672         value: value,
28673         predicateValues: predicates.map(function(predicate) {
28674           return getPredicateValue(predicate.get(value), index);
28675         })
28676       };
28677     }
28678
28679     function doComparison(v1, v2) {
28680       var result = 0;
28681       for (var index=0, length = predicates.length; index < length; ++index) {
28682         result = compare(v1.predicateValues[index], v2.predicateValues[index]) * predicates[index].descending;
28683         if (result) break;
28684       }
28685       return result;
28686     }
28687   };
28688
28689   function processPredicates(sortPredicate, reverseOrder) {
28690     reverseOrder = reverseOrder ? -1 : 1;
28691     return sortPredicate.map(function(predicate) {
28692       var descending = 1, get = identity;
28693
28694       if (isFunction(predicate)) {
28695         get = predicate;
28696       } else if (isString(predicate)) {
28697         if ((predicate.charAt(0) == '+' || predicate.charAt(0) == '-')) {
28698           descending = predicate.charAt(0) == '-' ? -1 : 1;
28699           predicate = predicate.substring(1);
28700         }
28701         if (predicate !== '') {
28702           get = $parse(predicate);
28703           if (get.constant) {
28704             var key = get();
28705             get = function(value) { return value[key]; };
28706           }
28707         }
28708       }
28709       return { get: get, descending: descending * reverseOrder };
28710     });
28711   }
28712
28713   function isPrimitive(value) {
28714     switch (typeof value) {
28715       case 'number': /* falls through */
28716       case 'boolean': /* falls through */
28717       case 'string':
28718         return true;
28719       default:
28720         return false;
28721     }
28722   }
28723
28724   function objectValue(value, index) {
28725     // If `valueOf` is a valid function use that
28726     if (typeof value.valueOf === 'function') {
28727       value = value.valueOf();
28728       if (isPrimitive(value)) return value;
28729     }
28730     // If `toString` is a valid function and not the one from `Object.prototype` use that
28731     if (hasCustomToString(value)) {
28732       value = value.toString();
28733       if (isPrimitive(value)) return value;
28734     }
28735     // We have a basic object so we use the position of the object in the collection
28736     return index;
28737   }
28738
28739   function getPredicateValue(value, index) {
28740     var type = typeof value;
28741     if (value === null) {
28742       type = 'string';
28743       value = 'null';
28744     } else if (type === 'string') {
28745       value = value.toLowerCase();
28746     } else if (type === 'object') {
28747       value = objectValue(value, index);
28748     }
28749     return { value: value, type: type };
28750   }
28751
28752   function compare(v1, v2) {
28753     var result = 0;
28754     if (v1.type === v2.type) {
28755       if (v1.value !== v2.value) {
28756         result = v1.value < v2.value ? -1 : 1;
28757       }
28758     } else {
28759       result = v1.type < v2.type ? -1 : 1;
28760     }
28761     return result;
28762   }
28763 }
28764
28765 function ngDirective(directive) {
28766   if (isFunction(directive)) {
28767     directive = {
28768       link: directive
28769     };
28770   }
28771   directive.restrict = directive.restrict || 'AC';
28772   return valueFn(directive);
28773 }
28774
28775 /**
28776  * @ngdoc directive
28777  * @name a
28778  * @restrict E
28779  *
28780  * @description
28781  * Modifies the default behavior of the html A tag so that the default action is prevented when
28782  * the href attribute is empty.
28783  *
28784  * This change permits the easy creation of action links with the `ngClick` directive
28785  * without changing the location or causing page reloads, e.g.:
28786  * `<a href="" ng-click="list.addItem()">Add Item</a>`
28787  */
28788 var htmlAnchorDirective = valueFn({
28789   restrict: 'E',
28790   compile: function(element, attr) {
28791     if (!attr.href && !attr.xlinkHref) {
28792       return function(scope, element) {
28793         // If the linked element is not an anchor tag anymore, do nothing
28794         if (element[0].nodeName.toLowerCase() !== 'a') return;
28795
28796         // SVGAElement does not use the href attribute, but rather the 'xlinkHref' attribute.
28797         var href = toString.call(element.prop('href')) === '[object SVGAnimatedString]' ?
28798                    'xlink:href' : 'href';
28799         element.on('click', function(event) {
28800           // if we have no href url, then don't navigate anywhere.
28801           if (!element.attr(href)) {
28802             event.preventDefault();
28803           }
28804         });
28805       };
28806     }
28807   }
28808 });
28809
28810 /**
28811  * @ngdoc directive
28812  * @name ngHref
28813  * @restrict A
28814  * @priority 99
28815  *
28816  * @description
28817  * Using Angular markup like `{{hash}}` in an href attribute will
28818  * make the link go to the wrong URL if the user clicks it before
28819  * Angular has a chance to replace the `{{hash}}` markup with its
28820  * value. Until Angular replaces the markup the link will be broken
28821  * and will most likely return a 404 error. The `ngHref` directive
28822  * solves this problem.
28823  *
28824  * The wrong way to write it:
28825  * ```html
28826  * <a href="http://www.gravatar.com/avatar/{{hash}}">link1</a>
28827  * ```
28828  *
28829  * The correct way to write it:
28830  * ```html
28831  * <a ng-href="http://www.gravatar.com/avatar/{{hash}}">link1</a>
28832  * ```
28833  *
28834  * @element A
28835  * @param {template} ngHref any string which can contain `{{}}` markup.
28836  *
28837  * @example
28838  * This example shows various combinations of `href`, `ng-href` and `ng-click` attributes
28839  * in links and their different behaviors:
28840     <example>
28841       <file name="index.html">
28842         <input ng-model="value" /><br />
28843         <a id="link-1" href ng-click="value = 1">link 1</a> (link, don't reload)<br />
28844         <a id="link-2" href="" ng-click="value = 2">link 2</a> (link, don't reload)<br />
28845         <a id="link-3" ng-href="/{{'123'}}">link 3</a> (link, reload!)<br />
28846         <a id="link-4" href="" name="xx" ng-click="value = 4">anchor</a> (link, don't reload)<br />
28847         <a id="link-5" name="xxx" ng-click="value = 5">anchor</a> (no link)<br />
28848         <a id="link-6" ng-href="{{value}}">link</a> (link, change location)
28849       </file>
28850       <file name="protractor.js" type="protractor">
28851         it('should execute ng-click but not reload when href without value', function() {
28852           element(by.id('link-1')).click();
28853           expect(element(by.model('value')).getAttribute('value')).toEqual('1');
28854           expect(element(by.id('link-1')).getAttribute('href')).toBe('');
28855         });
28856
28857         it('should execute ng-click but not reload when href empty string', function() {
28858           element(by.id('link-2')).click();
28859           expect(element(by.model('value')).getAttribute('value')).toEqual('2');
28860           expect(element(by.id('link-2')).getAttribute('href')).toBe('');
28861         });
28862
28863         it('should execute ng-click and change url when ng-href specified', function() {
28864           expect(element(by.id('link-3')).getAttribute('href')).toMatch(/\/123$/);
28865
28866           element(by.id('link-3')).click();
28867
28868           // At this point, we navigate away from an Angular page, so we need
28869           // to use browser.driver to get the base webdriver.
28870
28871           browser.wait(function() {
28872             return browser.driver.getCurrentUrl().then(function(url) {
28873               return url.match(/\/123$/);
28874             });
28875           }, 5000, 'page should navigate to /123');
28876         });
28877
28878         it('should execute ng-click but not reload when href empty string and name specified', function() {
28879           element(by.id('link-4')).click();
28880           expect(element(by.model('value')).getAttribute('value')).toEqual('4');
28881           expect(element(by.id('link-4')).getAttribute('href')).toBe('');
28882         });
28883
28884         it('should execute ng-click but not reload when no href but name specified', function() {
28885           element(by.id('link-5')).click();
28886           expect(element(by.model('value')).getAttribute('value')).toEqual('5');
28887           expect(element(by.id('link-5')).getAttribute('href')).toBe(null);
28888         });
28889
28890         it('should only change url when only ng-href', function() {
28891           element(by.model('value')).clear();
28892           element(by.model('value')).sendKeys('6');
28893           expect(element(by.id('link-6')).getAttribute('href')).toMatch(/\/6$/);
28894
28895           element(by.id('link-6')).click();
28896
28897           // At this point, we navigate away from an Angular page, so we need
28898           // to use browser.driver to get the base webdriver.
28899           browser.wait(function() {
28900             return browser.driver.getCurrentUrl().then(function(url) {
28901               return url.match(/\/6$/);
28902             });
28903           }, 5000, 'page should navigate to /6');
28904         });
28905       </file>
28906     </example>
28907  */
28908
28909 /**
28910  * @ngdoc directive
28911  * @name ngSrc
28912  * @restrict A
28913  * @priority 99
28914  *
28915  * @description
28916  * Using Angular markup like `{{hash}}` in a `src` attribute doesn't
28917  * work right: The browser will fetch from the URL with the literal
28918  * text `{{hash}}` until Angular replaces the expression inside
28919  * `{{hash}}`. The `ngSrc` directive solves this problem.
28920  *
28921  * The buggy way to write it:
28922  * ```html
28923  * <img src="http://www.gravatar.com/avatar/{{hash}}" alt="Description"/>
28924  * ```
28925  *
28926  * The correct way to write it:
28927  * ```html
28928  * <img ng-src="http://www.gravatar.com/avatar/{{hash}}" alt="Description" />
28929  * ```
28930  *
28931  * @element IMG
28932  * @param {template} ngSrc any string which can contain `{{}}` markup.
28933  */
28934
28935 /**
28936  * @ngdoc directive
28937  * @name ngSrcset
28938  * @restrict A
28939  * @priority 99
28940  *
28941  * @description
28942  * Using Angular markup like `{{hash}}` in a `srcset` attribute doesn't
28943  * work right: The browser will fetch from the URL with the literal
28944  * text `{{hash}}` until Angular replaces the expression inside
28945  * `{{hash}}`. The `ngSrcset` directive solves this problem.
28946  *
28947  * The buggy way to write it:
28948  * ```html
28949  * <img srcset="http://www.gravatar.com/avatar/{{hash}} 2x" alt="Description"/>
28950  * ```
28951  *
28952  * The correct way to write it:
28953  * ```html
28954  * <img ng-srcset="http://www.gravatar.com/avatar/{{hash}} 2x" alt="Description" />
28955  * ```
28956  *
28957  * @element IMG
28958  * @param {template} ngSrcset any string which can contain `{{}}` markup.
28959  */
28960
28961 /**
28962  * @ngdoc directive
28963  * @name ngDisabled
28964  * @restrict A
28965  * @priority 100
28966  *
28967  * @description
28968  *
28969  * This directive sets the `disabled` attribute on the element if the
28970  * {@link guide/expression expression} inside `ngDisabled` evaluates to truthy.
28971  *
28972  * A special directive is necessary because we cannot use interpolation inside the `disabled`
28973  * attribute.  The following example would make the button enabled on Chrome/Firefox
28974  * but not on older IEs:
28975  *
28976  * ```html
28977  * <!-- See below for an example of ng-disabled being used correctly -->
28978  * <div ng-init="isDisabled = false">
28979  *  <button disabled="{{isDisabled}}">Disabled</button>
28980  * </div>
28981  * ```
28982  *
28983  * This is because the HTML specification does not require browsers to preserve the values of
28984  * boolean attributes such as `disabled` (Their presence means true and their absence means false.)
28985  * If we put an Angular interpolation expression into such an attribute then the
28986  * binding information would be lost when the browser removes the attribute.
28987  *
28988  * @example
28989     <example>
28990       <file name="index.html">
28991         <label>Click me to toggle: <input type="checkbox" ng-model="checked"></label><br/>
28992         <button ng-model="button" ng-disabled="checked">Button</button>
28993       </file>
28994       <file name="protractor.js" type="protractor">
28995         it('should toggle button', function() {
28996           expect(element(by.css('button')).getAttribute('disabled')).toBeFalsy();
28997           element(by.model('checked')).click();
28998           expect(element(by.css('button')).getAttribute('disabled')).toBeTruthy();
28999         });
29000       </file>
29001     </example>
29002  *
29003  * @element INPUT
29004  * @param {expression} ngDisabled If the {@link guide/expression expression} is truthy,
29005  *     then the `disabled` attribute will be set on the element
29006  */
29007
29008
29009 /**
29010  * @ngdoc directive
29011  * @name ngChecked
29012  * @restrict A
29013  * @priority 100
29014  *
29015  * @description
29016  * Sets the `checked` attribute on the element, if the expression inside `ngChecked` is truthy.
29017  *
29018  * Note that this directive should not be used together with {@link ngModel `ngModel`},
29019  * as this can lead to unexpected behavior.
29020  *
29021  * ### Why do we need `ngChecked`?
29022  *
29023  * The HTML specification does not require browsers to preserve the values of boolean attributes
29024  * such as checked. (Their presence means true and their absence means false.)
29025  * If we put an Angular interpolation expression into such an attribute then the
29026  * binding information would be lost when the browser removes the attribute.
29027  * The `ngChecked` directive solves this problem for the `checked` attribute.
29028  * This complementary directive is not removed by the browser and so provides
29029  * a permanent reliable place to store the binding information.
29030  * @example
29031     <example>
29032       <file name="index.html">
29033         <label>Check me to check both: <input type="checkbox" ng-model="master"></label><br/>
29034         <input id="checkSlave" type="checkbox" ng-checked="master" aria-label="Slave input">
29035       </file>
29036       <file name="protractor.js" type="protractor">
29037         it('should check both checkBoxes', function() {
29038           expect(element(by.id('checkSlave')).getAttribute('checked')).toBeFalsy();
29039           element(by.model('master')).click();
29040           expect(element(by.id('checkSlave')).getAttribute('checked')).toBeTruthy();
29041         });
29042       </file>
29043     </example>
29044  *
29045  * @element INPUT
29046  * @param {expression} ngChecked If the {@link guide/expression expression} is truthy,
29047  *     then the `checked` attribute will be set on the element
29048  */
29049
29050
29051 /**
29052  * @ngdoc directive
29053  * @name ngReadonly
29054  * @restrict A
29055  * @priority 100
29056  *
29057  * @description
29058  * The HTML specification does not require browsers to preserve the values of boolean attributes
29059  * such as readonly. (Their presence means true and their absence means false.)
29060  * If we put an Angular interpolation expression into such an attribute then the
29061  * binding information would be lost when the browser removes the attribute.
29062  * The `ngReadonly` directive solves this problem for the `readonly` attribute.
29063  * This complementary directive is not removed by the browser and so provides
29064  * a permanent reliable place to store the binding information.
29065  * @example
29066     <example>
29067       <file name="index.html">
29068         <label>Check me to make text readonly: <input type="checkbox" ng-model="checked"></label><br/>
29069         <input type="text" ng-readonly="checked" value="I'm Angular" aria-label="Readonly field" />
29070       </file>
29071       <file name="protractor.js" type="protractor">
29072         it('should toggle readonly attr', function() {
29073           expect(element(by.css('[type="text"]')).getAttribute('readonly')).toBeFalsy();
29074           element(by.model('checked')).click();
29075           expect(element(by.css('[type="text"]')).getAttribute('readonly')).toBeTruthy();
29076         });
29077       </file>
29078     </example>
29079  *
29080  * @element INPUT
29081  * @param {expression} ngReadonly If the {@link guide/expression expression} is truthy,
29082  *     then special attribute "readonly" will be set on the element
29083  */
29084
29085
29086 /**
29087  * @ngdoc directive
29088  * @name ngSelected
29089  * @restrict A
29090  * @priority 100
29091  *
29092  * @description
29093  * The HTML specification does not require browsers to preserve the values of boolean attributes
29094  * such as selected. (Their presence means true and their absence means false.)
29095  * If we put an Angular interpolation expression into such an attribute then the
29096  * binding information would be lost when the browser removes the attribute.
29097  * The `ngSelected` directive solves this problem for the `selected` attribute.
29098  * This complementary directive is not removed by the browser and so provides
29099  * a permanent reliable place to store the binding information.
29100  *
29101  * @example
29102     <example>
29103       <file name="index.html">
29104         <label>Check me to select: <input type="checkbox" ng-model="selected"></label><br/>
29105         <select aria-label="ngSelected demo">
29106           <option>Hello!</option>
29107           <option id="greet" ng-selected="selected">Greetings!</option>
29108         </select>
29109       </file>
29110       <file name="protractor.js" type="protractor">
29111         it('should select Greetings!', function() {
29112           expect(element(by.id('greet')).getAttribute('selected')).toBeFalsy();
29113           element(by.model('selected')).click();
29114           expect(element(by.id('greet')).getAttribute('selected')).toBeTruthy();
29115         });
29116       </file>
29117     </example>
29118  *
29119  * @element OPTION
29120  * @param {expression} ngSelected If the {@link guide/expression expression} is truthy,
29121  *     then special attribute "selected" will be set on the element
29122  */
29123
29124 /**
29125  * @ngdoc directive
29126  * @name ngOpen
29127  * @restrict A
29128  * @priority 100
29129  *
29130  * @description
29131  * The HTML specification does not require browsers to preserve the values of boolean attributes
29132  * such as open. (Their presence means true and their absence means false.)
29133  * If we put an Angular interpolation expression into such an attribute then the
29134  * binding information would be lost when the browser removes the attribute.
29135  * The `ngOpen` directive solves this problem for the `open` attribute.
29136  * This complementary directive is not removed by the browser and so provides
29137  * a permanent reliable place to store the binding information.
29138  * @example
29139      <example>
29140        <file name="index.html">
29141          <label>Check me check multiple: <input type="checkbox" ng-model="open"></label><br/>
29142          <details id="details" ng-open="open">
29143             <summary>Show/Hide me</summary>
29144          </details>
29145        </file>
29146        <file name="protractor.js" type="protractor">
29147          it('should toggle open', function() {
29148            expect(element(by.id('details')).getAttribute('open')).toBeFalsy();
29149            element(by.model('open')).click();
29150            expect(element(by.id('details')).getAttribute('open')).toBeTruthy();
29151          });
29152        </file>
29153      </example>
29154  *
29155  * @element DETAILS
29156  * @param {expression} ngOpen If the {@link guide/expression expression} is truthy,
29157  *     then special attribute "open" will be set on the element
29158  */
29159
29160 var ngAttributeAliasDirectives = {};
29161
29162 // boolean attrs are evaluated
29163 forEach(BOOLEAN_ATTR, function(propName, attrName) {
29164   // binding to multiple is not supported
29165   if (propName == "multiple") return;
29166
29167   function defaultLinkFn(scope, element, attr) {
29168     scope.$watch(attr[normalized], function ngBooleanAttrWatchAction(value) {
29169       attr.$set(attrName, !!value);
29170     });
29171   }
29172
29173   var normalized = directiveNormalize('ng-' + attrName);
29174   var linkFn = defaultLinkFn;
29175
29176   if (propName === 'checked') {
29177     linkFn = function(scope, element, attr) {
29178       // ensuring ngChecked doesn't interfere with ngModel when both are set on the same input
29179       if (attr.ngModel !== attr[normalized]) {
29180         defaultLinkFn(scope, element, attr);
29181       }
29182     };
29183   }
29184
29185   ngAttributeAliasDirectives[normalized] = function() {
29186     return {
29187       restrict: 'A',
29188       priority: 100,
29189       link: linkFn
29190     };
29191   };
29192 });
29193
29194 // aliased input attrs are evaluated
29195 forEach(ALIASED_ATTR, function(htmlAttr, ngAttr) {
29196   ngAttributeAliasDirectives[ngAttr] = function() {
29197     return {
29198       priority: 100,
29199       link: function(scope, element, attr) {
29200         //special case ngPattern when a literal regular expression value
29201         //is used as the expression (this way we don't have to watch anything).
29202         if (ngAttr === "ngPattern" && attr.ngPattern.charAt(0) == "/") {
29203           var match = attr.ngPattern.match(REGEX_STRING_REGEXP);
29204           if (match) {
29205             attr.$set("ngPattern", new RegExp(match[1], match[2]));
29206             return;
29207           }
29208         }
29209
29210         scope.$watch(attr[ngAttr], function ngAttrAliasWatchAction(value) {
29211           attr.$set(ngAttr, value);
29212         });
29213       }
29214     };
29215   };
29216 });
29217
29218 // ng-src, ng-srcset, ng-href are interpolated
29219 forEach(['src', 'srcset', 'href'], function(attrName) {
29220   var normalized = directiveNormalize('ng-' + attrName);
29221   ngAttributeAliasDirectives[normalized] = function() {
29222     return {
29223       priority: 99, // it needs to run after the attributes are interpolated
29224       link: function(scope, element, attr) {
29225         var propName = attrName,
29226             name = attrName;
29227
29228         if (attrName === 'href' &&
29229             toString.call(element.prop('href')) === '[object SVGAnimatedString]') {
29230           name = 'xlinkHref';
29231           attr.$attr[name] = 'xlink:href';
29232           propName = null;
29233         }
29234
29235         attr.$observe(normalized, function(value) {
29236           if (!value) {
29237             if (attrName === 'href') {
29238               attr.$set(name, null);
29239             }
29240             return;
29241           }
29242
29243           attr.$set(name, value);
29244
29245           // on IE, if "ng:src" directive declaration is used and "src" attribute doesn't exist
29246           // then calling element.setAttribute('src', 'foo') doesn't do anything, so we need
29247           // to set the property as well to achieve the desired effect.
29248           // we use attr[attrName] value since $set can sanitize the url.
29249           if (msie && propName) element.prop(propName, attr[name]);
29250         });
29251       }
29252     };
29253   };
29254 });
29255
29256 /* global -nullFormCtrl, -SUBMITTED_CLASS, addSetValidityMethod: true
29257  */
29258 var nullFormCtrl = {
29259   $addControl: noop,
29260   $$renameControl: nullFormRenameControl,
29261   $removeControl: noop,
29262   $setValidity: noop,
29263   $setDirty: noop,
29264   $setPristine: noop,
29265   $setSubmitted: noop
29266 },
29267 SUBMITTED_CLASS = 'ng-submitted';
29268
29269 function nullFormRenameControl(control, name) {
29270   control.$name = name;
29271 }
29272
29273 /**
29274  * @ngdoc type
29275  * @name form.FormController
29276  *
29277  * @property {boolean} $pristine True if user has not interacted with the form yet.
29278  * @property {boolean} $dirty True if user has already interacted with the form.
29279  * @property {boolean} $valid True if all of the containing forms and controls are valid.
29280  * @property {boolean} $invalid True if at least one containing control or form is invalid.
29281  * @property {boolean} $pending True if at least one containing control or form is pending.
29282  * @property {boolean} $submitted True if user has submitted the form even if its invalid.
29283  *
29284  * @property {Object} $error Is an object hash, containing references to controls or
29285  *  forms with failing validators, where:
29286  *
29287  *  - keys are validation tokens (error names),
29288  *  - values are arrays of controls or forms that have a failing validator for given error name.
29289  *
29290  *  Built-in validation tokens:
29291  *
29292  *  - `email`
29293  *  - `max`
29294  *  - `maxlength`
29295  *  - `min`
29296  *  - `minlength`
29297  *  - `number`
29298  *  - `pattern`
29299  *  - `required`
29300  *  - `url`
29301  *  - `date`
29302  *  - `datetimelocal`
29303  *  - `time`
29304  *  - `week`
29305  *  - `month`
29306  *
29307  * @description
29308  * `FormController` keeps track of all its controls and nested forms as well as the state of them,
29309  * such as being valid/invalid or dirty/pristine.
29310  *
29311  * Each {@link ng.directive:form form} directive creates an instance
29312  * of `FormController`.
29313  *
29314  */
29315 //asks for $scope to fool the BC controller module
29316 FormController.$inject = ['$element', '$attrs', '$scope', '$animate', '$interpolate'];
29317 function FormController(element, attrs, $scope, $animate, $interpolate) {
29318   var form = this,
29319       controls = [];
29320
29321   // init state
29322   form.$error = {};
29323   form.$$success = {};
29324   form.$pending = undefined;
29325   form.$name = $interpolate(attrs.name || attrs.ngForm || '')($scope);
29326   form.$dirty = false;
29327   form.$pristine = true;
29328   form.$valid = true;
29329   form.$invalid = false;
29330   form.$submitted = false;
29331   form.$$parentForm = nullFormCtrl;
29332
29333   /**
29334    * @ngdoc method
29335    * @name form.FormController#$rollbackViewValue
29336    *
29337    * @description
29338    * Rollback all form controls pending updates to the `$modelValue`.
29339    *
29340    * Updates may be pending by a debounced event or because the input is waiting for a some future
29341    * event defined in `ng-model-options`. This method is typically needed by the reset button of
29342    * a form that uses `ng-model-options` to pend updates.
29343    */
29344   form.$rollbackViewValue = function() {
29345     forEach(controls, function(control) {
29346       control.$rollbackViewValue();
29347     });
29348   };
29349
29350   /**
29351    * @ngdoc method
29352    * @name form.FormController#$commitViewValue
29353    *
29354    * @description
29355    * Commit all form controls pending updates to the `$modelValue`.
29356    *
29357    * Updates may be pending by a debounced event or because the input is waiting for a some future
29358    * event defined in `ng-model-options`. This method is rarely needed as `NgModelController`
29359    * usually handles calling this in response to input events.
29360    */
29361   form.$commitViewValue = function() {
29362     forEach(controls, function(control) {
29363       control.$commitViewValue();
29364     });
29365   };
29366
29367   /**
29368    * @ngdoc method
29369    * @name form.FormController#$addControl
29370    * @param {object} control control object, either a {@link form.FormController} or an
29371    * {@link ngModel.NgModelController}
29372    *
29373    * @description
29374    * Register a control with the form. Input elements using ngModelController do this automatically
29375    * when they are linked.
29376    *
29377    * Note that the current state of the control will not be reflected on the new parent form. This
29378    * is not an issue with normal use, as freshly compiled and linked controls are in a `$pristine`
29379    * state.
29380    *
29381    * However, if the method is used programmatically, for example by adding dynamically created controls,
29382    * or controls that have been previously removed without destroying their corresponding DOM element,
29383    * it's the developers responsiblity to make sure the current state propagates to the parent form.
29384    *
29385    * For example, if an input control is added that is already `$dirty` and has `$error` properties,
29386    * calling `$setDirty()` and `$validate()` afterwards will propagate the state to the parent form.
29387    */
29388   form.$addControl = function(control) {
29389     // Breaking change - before, inputs whose name was "hasOwnProperty" were quietly ignored
29390     // and not added to the scope.  Now we throw an error.
29391     assertNotHasOwnProperty(control.$name, 'input');
29392     controls.push(control);
29393
29394     if (control.$name) {
29395       form[control.$name] = control;
29396     }
29397
29398     control.$$parentForm = form;
29399   };
29400
29401   // Private API: rename a form control
29402   form.$$renameControl = function(control, newName) {
29403     var oldName = control.$name;
29404
29405     if (form[oldName] === control) {
29406       delete form[oldName];
29407     }
29408     form[newName] = control;
29409     control.$name = newName;
29410   };
29411
29412   /**
29413    * @ngdoc method
29414    * @name form.FormController#$removeControl
29415    * @param {object} control control object, either a {@link form.FormController} or an
29416    * {@link ngModel.NgModelController}
29417    *
29418    * @description
29419    * Deregister a control from the form.
29420    *
29421    * Input elements using ngModelController do this automatically when they are destroyed.
29422    *
29423    * Note that only the removed control's validation state (`$errors`etc.) will be removed from the
29424    * form. `$dirty`, `$submitted` states will not be changed, because the expected behavior can be
29425    * different from case to case. For example, removing the only `$dirty` control from a form may or
29426    * may not mean that the form is still `$dirty`.
29427    */
29428   form.$removeControl = function(control) {
29429     if (control.$name && form[control.$name] === control) {
29430       delete form[control.$name];
29431     }
29432     forEach(form.$pending, function(value, name) {
29433       form.$setValidity(name, null, control);
29434     });
29435     forEach(form.$error, function(value, name) {
29436       form.$setValidity(name, null, control);
29437     });
29438     forEach(form.$$success, function(value, name) {
29439       form.$setValidity(name, null, control);
29440     });
29441
29442     arrayRemove(controls, control);
29443     control.$$parentForm = nullFormCtrl;
29444   };
29445
29446
29447   /**
29448    * @ngdoc method
29449    * @name form.FormController#$setValidity
29450    *
29451    * @description
29452    * Sets the validity of a form control.
29453    *
29454    * This method will also propagate to parent forms.
29455    */
29456   addSetValidityMethod({
29457     ctrl: this,
29458     $element: element,
29459     set: function(object, property, controller) {
29460       var list = object[property];
29461       if (!list) {
29462         object[property] = [controller];
29463       } else {
29464         var index = list.indexOf(controller);
29465         if (index === -1) {
29466           list.push(controller);
29467         }
29468       }
29469     },
29470     unset: function(object, property, controller) {
29471       var list = object[property];
29472       if (!list) {
29473         return;
29474       }
29475       arrayRemove(list, controller);
29476       if (list.length === 0) {
29477         delete object[property];
29478       }
29479     },
29480     $animate: $animate
29481   });
29482
29483   /**
29484    * @ngdoc method
29485    * @name form.FormController#$setDirty
29486    *
29487    * @description
29488    * Sets the form to a dirty state.
29489    *
29490    * This method can be called to add the 'ng-dirty' class and set the form to a dirty
29491    * state (ng-dirty class). This method will also propagate to parent forms.
29492    */
29493   form.$setDirty = function() {
29494     $animate.removeClass(element, PRISTINE_CLASS);
29495     $animate.addClass(element, DIRTY_CLASS);
29496     form.$dirty = true;
29497     form.$pristine = false;
29498     form.$$parentForm.$setDirty();
29499   };
29500
29501   /**
29502    * @ngdoc method
29503    * @name form.FormController#$setPristine
29504    *
29505    * @description
29506    * Sets the form to its pristine state.
29507    *
29508    * This method can be called to remove the 'ng-dirty' class and set the form to its pristine
29509    * state (ng-pristine class). This method will also propagate to all the controls contained
29510    * in this form.
29511    *
29512    * Setting a form back to a pristine state is often useful when we want to 'reuse' a form after
29513    * saving or resetting it.
29514    */
29515   form.$setPristine = function() {
29516     $animate.setClass(element, PRISTINE_CLASS, DIRTY_CLASS + ' ' + SUBMITTED_CLASS);
29517     form.$dirty = false;
29518     form.$pristine = true;
29519     form.$submitted = false;
29520     forEach(controls, function(control) {
29521       control.$setPristine();
29522     });
29523   };
29524
29525   /**
29526    * @ngdoc method
29527    * @name form.FormController#$setUntouched
29528    *
29529    * @description
29530    * Sets the form to its untouched state.
29531    *
29532    * This method can be called to remove the 'ng-touched' class and set the form controls to their
29533    * untouched state (ng-untouched class).
29534    *
29535    * Setting a form controls back to their untouched state is often useful when setting the form
29536    * back to its pristine state.
29537    */
29538   form.$setUntouched = function() {
29539     forEach(controls, function(control) {
29540       control.$setUntouched();
29541     });
29542   };
29543
29544   /**
29545    * @ngdoc method
29546    * @name form.FormController#$setSubmitted
29547    *
29548    * @description
29549    * Sets the form to its submitted state.
29550    */
29551   form.$setSubmitted = function() {
29552     $animate.addClass(element, SUBMITTED_CLASS);
29553     form.$submitted = true;
29554     form.$$parentForm.$setSubmitted();
29555   };
29556 }
29557
29558 /**
29559  * @ngdoc directive
29560  * @name ngForm
29561  * @restrict EAC
29562  *
29563  * @description
29564  * Nestable alias of {@link ng.directive:form `form`} directive. HTML
29565  * does not allow nesting of form elements. It is useful to nest forms, for example if the validity of a
29566  * sub-group of controls needs to be determined.
29567  *
29568  * Note: the purpose of `ngForm` is to group controls,
29569  * but not to be a replacement for the `<form>` tag with all of its capabilities
29570  * (e.g. posting to the server, ...).
29571  *
29572  * @param {string=} ngForm|name Name of the form. If specified, the form controller will be published into
29573  *                       related scope, under this name.
29574  *
29575  */
29576
29577  /**
29578  * @ngdoc directive
29579  * @name form
29580  * @restrict E
29581  *
29582  * @description
29583  * Directive that instantiates
29584  * {@link form.FormController FormController}.
29585  *
29586  * If the `name` attribute is specified, the form controller is published onto the current scope under
29587  * this name.
29588  *
29589  * # Alias: {@link ng.directive:ngForm `ngForm`}
29590  *
29591  * In Angular, forms can be nested. This means that the outer form is valid when all of the child
29592  * forms are valid as well. However, browsers do not allow nesting of `<form>` elements, so
29593  * Angular provides the {@link ng.directive:ngForm `ngForm`} directive which behaves identically to
29594  * `<form>` but can be nested.  This allows you to have nested forms, which is very useful when
29595  * using Angular validation directives in forms that are dynamically generated using the
29596  * {@link ng.directive:ngRepeat `ngRepeat`} directive. Since you cannot dynamically generate the `name`
29597  * attribute of input elements using interpolation, you have to wrap each set of repeated inputs in an
29598  * `ngForm` directive and nest these in an outer `form` element.
29599  *
29600  *
29601  * # CSS classes
29602  *  - `ng-valid` is set if the form is valid.
29603  *  - `ng-invalid` is set if the form is invalid.
29604  *  - `ng-pending` is set if the form is pending.
29605  *  - `ng-pristine` is set if the form is pristine.
29606  *  - `ng-dirty` is set if the form is dirty.
29607  *  - `ng-submitted` is set if the form was submitted.
29608  *
29609  * Keep in mind that ngAnimate can detect each of these classes when added and removed.
29610  *
29611  *
29612  * # Submitting a form and preventing the default action
29613  *
29614  * Since the role of forms in client-side Angular applications is different than in classical
29615  * roundtrip apps, it is desirable for the browser not to translate the form submission into a full
29616  * page reload that sends the data to the server. Instead some javascript logic should be triggered
29617  * to handle the form submission in an application-specific way.
29618  *
29619  * For this reason, Angular prevents the default action (form submission to the server) unless the
29620  * `<form>` element has an `action` attribute specified.
29621  *
29622  * You can use one of the following two ways to specify what javascript method should be called when
29623  * a form is submitted:
29624  *
29625  * - {@link ng.directive:ngSubmit ngSubmit} directive on the form element
29626  * - {@link ng.directive:ngClick ngClick} directive on the first
29627   *  button or input field of type submit (input[type=submit])
29628  *
29629  * To prevent double execution of the handler, use only one of the {@link ng.directive:ngSubmit ngSubmit}
29630  * or {@link ng.directive:ngClick ngClick} directives.
29631  * This is because of the following form submission rules in the HTML specification:
29632  *
29633  * - If a form has only one input field then hitting enter in this field triggers form submit
29634  * (`ngSubmit`)
29635  * - if a form has 2+ input fields and no buttons or input[type=submit] then hitting enter
29636  * doesn't trigger submit
29637  * - if a form has one or more input fields and one or more buttons or input[type=submit] then
29638  * hitting enter in any of the input fields will trigger the click handler on the *first* button or
29639  * input[type=submit] (`ngClick`) *and* a submit handler on the enclosing form (`ngSubmit`)
29640  *
29641  * Any pending `ngModelOptions` changes will take place immediately when an enclosing form is
29642  * submitted. Note that `ngClick` events will occur before the model is updated. Use `ngSubmit`
29643  * to have access to the updated model.
29644  *
29645  * ## Animation Hooks
29646  *
29647  * Animations in ngForm are triggered when any of the associated CSS classes are added and removed.
29648  * These classes are: `.ng-pristine`, `.ng-dirty`, `.ng-invalid` and `.ng-valid` as well as any
29649  * other validations that are performed within the form. Animations in ngForm are similar to how
29650  * they work in ngClass and animations can be hooked into using CSS transitions, keyframes as well
29651  * as JS animations.
29652  *
29653  * The following example shows a simple way to utilize CSS transitions to style a form element
29654  * that has been rendered as invalid after it has been validated:
29655  *
29656  * <pre>
29657  * //be sure to include ngAnimate as a module to hook into more
29658  * //advanced animations
29659  * .my-form {
29660  *   transition:0.5s linear all;
29661  *   background: white;
29662  * }
29663  * .my-form.ng-invalid {
29664  *   background: red;
29665  *   color:white;
29666  * }
29667  * </pre>
29668  *
29669  * @example
29670     <example deps="angular-animate.js" animations="true" fixBase="true" module="formExample">
29671       <file name="index.html">
29672        <script>
29673          angular.module('formExample', [])
29674            .controller('FormController', ['$scope', function($scope) {
29675              $scope.userType = 'guest';
29676            }]);
29677        </script>
29678        <style>
29679         .my-form {
29680           transition:all linear 0.5s;
29681           background: transparent;
29682         }
29683         .my-form.ng-invalid {
29684           background: red;
29685         }
29686        </style>
29687        <form name="myForm" ng-controller="FormController" class="my-form">
29688          userType: <input name="input" ng-model="userType" required>
29689          <span class="error" ng-show="myForm.input.$error.required">Required!</span><br>
29690          <code>userType = {{userType}}</code><br>
29691          <code>myForm.input.$valid = {{myForm.input.$valid}}</code><br>
29692          <code>myForm.input.$error = {{myForm.input.$error}}</code><br>
29693          <code>myForm.$valid = {{myForm.$valid}}</code><br>
29694          <code>myForm.$error.required = {{!!myForm.$error.required}}</code><br>
29695         </form>
29696       </file>
29697       <file name="protractor.js" type="protractor">
29698         it('should initialize to model', function() {
29699           var userType = element(by.binding('userType'));
29700           var valid = element(by.binding('myForm.input.$valid'));
29701
29702           expect(userType.getText()).toContain('guest');
29703           expect(valid.getText()).toContain('true');
29704         });
29705
29706         it('should be invalid if empty', function() {
29707           var userType = element(by.binding('userType'));
29708           var valid = element(by.binding('myForm.input.$valid'));
29709           var userInput = element(by.model('userType'));
29710
29711           userInput.clear();
29712           userInput.sendKeys('');
29713
29714           expect(userType.getText()).toEqual('userType =');
29715           expect(valid.getText()).toContain('false');
29716         });
29717       </file>
29718     </example>
29719  *
29720  * @param {string=} name Name of the form. If specified, the form controller will be published into
29721  *                       related scope, under this name.
29722  */
29723 var formDirectiveFactory = function(isNgForm) {
29724   return ['$timeout', '$parse', function($timeout, $parse) {
29725     var formDirective = {
29726       name: 'form',
29727       restrict: isNgForm ? 'EAC' : 'E',
29728       require: ['form', '^^?form'], //first is the form's own ctrl, second is an optional parent form
29729       controller: FormController,
29730       compile: function ngFormCompile(formElement, attr) {
29731         // Setup initial state of the control
29732         formElement.addClass(PRISTINE_CLASS).addClass(VALID_CLASS);
29733
29734         var nameAttr = attr.name ? 'name' : (isNgForm && attr.ngForm ? 'ngForm' : false);
29735
29736         return {
29737           pre: function ngFormPreLink(scope, formElement, attr, ctrls) {
29738             var controller = ctrls[0];
29739
29740             // if `action` attr is not present on the form, prevent the default action (submission)
29741             if (!('action' in attr)) {
29742               // we can't use jq events because if a form is destroyed during submission the default
29743               // action is not prevented. see #1238
29744               //
29745               // IE 9 is not affected because it doesn't fire a submit event and try to do a full
29746               // page reload if the form was destroyed by submission of the form via a click handler
29747               // on a button in the form. Looks like an IE9 specific bug.
29748               var handleFormSubmission = function(event) {
29749                 scope.$apply(function() {
29750                   controller.$commitViewValue();
29751                   controller.$setSubmitted();
29752                 });
29753
29754                 event.preventDefault();
29755               };
29756
29757               addEventListenerFn(formElement[0], 'submit', handleFormSubmission);
29758
29759               // unregister the preventDefault listener so that we don't not leak memory but in a
29760               // way that will achieve the prevention of the default action.
29761               formElement.on('$destroy', function() {
29762                 $timeout(function() {
29763                   removeEventListenerFn(formElement[0], 'submit', handleFormSubmission);
29764                 }, 0, false);
29765               });
29766             }
29767
29768             var parentFormCtrl = ctrls[1] || controller.$$parentForm;
29769             parentFormCtrl.$addControl(controller);
29770
29771             var setter = nameAttr ? getSetter(controller.$name) : noop;
29772
29773             if (nameAttr) {
29774               setter(scope, controller);
29775               attr.$observe(nameAttr, function(newValue) {
29776                 if (controller.$name === newValue) return;
29777                 setter(scope, undefined);
29778                 controller.$$parentForm.$$renameControl(controller, newValue);
29779                 setter = getSetter(controller.$name);
29780                 setter(scope, controller);
29781               });
29782             }
29783             formElement.on('$destroy', function() {
29784               controller.$$parentForm.$removeControl(controller);
29785               setter(scope, undefined);
29786               extend(controller, nullFormCtrl); //stop propagating child destruction handlers upwards
29787             });
29788           }
29789         };
29790       }
29791     };
29792
29793     return formDirective;
29794
29795     function getSetter(expression) {
29796       if (expression === '') {
29797         //create an assignable expression, so forms with an empty name can be renamed later
29798         return $parse('this[""]').assign;
29799       }
29800       return $parse(expression).assign || noop;
29801     }
29802   }];
29803 };
29804
29805 var formDirective = formDirectiveFactory();
29806 var ngFormDirective = formDirectiveFactory(true);
29807
29808 /* global VALID_CLASS: false,
29809   INVALID_CLASS: false,
29810   PRISTINE_CLASS: false,
29811   DIRTY_CLASS: false,
29812   UNTOUCHED_CLASS: false,
29813   TOUCHED_CLASS: false,
29814   ngModelMinErr: false,
29815 */
29816
29817 // Regex code is obtained from SO: https://stackoverflow.com/questions/3143070/javascript-regex-iso-datetime#answer-3143231
29818 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)/;
29819 // See valid URLs in RFC3987 (http://tools.ietf.org/html/rfc3987)
29820 var URL_REGEXP = /^[A-Za-z][A-Za-z\d.+-]*:\/*(?:\w+(?::\w+)?@)?[^\s/]+(?::\d+)?(?:\/[\w#!:.?+=&%@\-/]*)?$/;
29821 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;
29822 var NUMBER_REGEXP = /^\s*(\-|\+)?(\d+|(\d*(\.\d*)))([eE][+-]?\d+)?\s*$/;
29823 var DATE_REGEXP = /^(\d{4})-(\d{2})-(\d{2})$/;
29824 var DATETIMELOCAL_REGEXP = /^(\d{4})-(\d\d)-(\d\d)T(\d\d):(\d\d)(?::(\d\d)(\.\d{1,3})?)?$/;
29825 var WEEK_REGEXP = /^(\d{4})-W(\d\d)$/;
29826 var MONTH_REGEXP = /^(\d{4})-(\d\d)$/;
29827 var TIME_REGEXP = /^(\d\d):(\d\d)(?::(\d\d)(\.\d{1,3})?)?$/;
29828
29829 var inputType = {
29830
29831   /**
29832    * @ngdoc input
29833    * @name input[text]
29834    *
29835    * @description
29836    * Standard HTML text input with angular data binding, inherited by most of the `input` elements.
29837    *
29838    *
29839    * @param {string} ngModel Assignable angular expression to data-bind to.
29840    * @param {string=} name Property name of the form under which the control is published.
29841    * @param {string=} required Adds `required` validation error key if the value is not entered.
29842    * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
29843    *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
29844    *    `required` when you want to data-bind to the `required` attribute.
29845    * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
29846    *    minlength.
29847    * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
29848    *    maxlength. Setting the attribute to a negative or non-numeric value, allows view values of
29849    *    any length.
29850    * @param {string=} pattern Similar to `ngPattern` except that the attribute value is the actual string
29851    *    that contains the regular expression body that will be converted to a regular expression
29852    *    as in the ngPattern directive.
29853    * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel value does not match
29854    *    a RegExp found by evaluating the Angular expression given in the attribute value.
29855    *    If the expression evaluates to a RegExp object, then this is used directly.
29856    *    If the expression evaluates to a string, then it will be converted to a RegExp
29857    *    after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to
29858    *    `new RegExp('^abc$')`.<br />
29859    *    **Note:** Avoid using the `g` flag on the RegExp, as it will cause each successive search to
29860    *    start at the index of the last search's match, thus not taking the whole input value into
29861    *    account.
29862    * @param {string=} ngChange Angular expression to be executed when input changes due to user
29863    *    interaction with the input element.
29864    * @param {boolean=} [ngTrim=true] If set to false Angular will not automatically trim the input.
29865    *    This parameter is ignored for input[type=password] controls, which will never trim the
29866    *    input.
29867    *
29868    * @example
29869       <example name="text-input-directive" module="textInputExample">
29870         <file name="index.html">
29871          <script>
29872            angular.module('textInputExample', [])
29873              .controller('ExampleController', ['$scope', function($scope) {
29874                $scope.example = {
29875                  text: 'guest',
29876                  word: /^\s*\w*\s*$/
29877                };
29878              }]);
29879          </script>
29880          <form name="myForm" ng-controller="ExampleController">
29881            <label>Single word:
29882              <input type="text" name="input" ng-model="example.text"
29883                     ng-pattern="example.word" required ng-trim="false">
29884            </label>
29885            <div role="alert">
29886              <span class="error" ng-show="myForm.input.$error.required">
29887                Required!</span>
29888              <span class="error" ng-show="myForm.input.$error.pattern">
29889                Single word only!</span>
29890            </div>
29891            <tt>text = {{example.text}}</tt><br/>
29892            <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
29893            <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
29894            <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
29895            <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
29896           </form>
29897         </file>
29898         <file name="protractor.js" type="protractor">
29899           var text = element(by.binding('example.text'));
29900           var valid = element(by.binding('myForm.input.$valid'));
29901           var input = element(by.model('example.text'));
29902
29903           it('should initialize to model', function() {
29904             expect(text.getText()).toContain('guest');
29905             expect(valid.getText()).toContain('true');
29906           });
29907
29908           it('should be invalid if empty', function() {
29909             input.clear();
29910             input.sendKeys('');
29911
29912             expect(text.getText()).toEqual('text =');
29913             expect(valid.getText()).toContain('false');
29914           });
29915
29916           it('should be invalid if multi word', function() {
29917             input.clear();
29918             input.sendKeys('hello world');
29919
29920             expect(valid.getText()).toContain('false');
29921           });
29922         </file>
29923       </example>
29924    */
29925   'text': textInputType,
29926
29927     /**
29928      * @ngdoc input
29929      * @name input[date]
29930      *
29931      * @description
29932      * Input with date validation and transformation. In browsers that do not yet support
29933      * the HTML5 date input, a text element will be used. In that case, text must be entered in a valid ISO-8601
29934      * date format (yyyy-MM-dd), for example: `2009-01-06`. Since many
29935      * modern browsers do not yet support this input type, it is important to provide cues to users on the
29936      * expected input format via a placeholder or label.
29937      *
29938      * The model must always be a Date object, otherwise Angular will throw an error.
29939      * Invalid `Date` objects (dates whose `getTime()` is `NaN`) will be rendered as an empty string.
29940      *
29941      * The timezone to be used to read/write the `Date` instance in the model can be defined using
29942      * {@link ng.directive:ngModelOptions ngModelOptions}. By default, this is the timezone of the browser.
29943      *
29944      * @param {string} ngModel Assignable angular expression to data-bind to.
29945      * @param {string=} name Property name of the form under which the control is published.
29946      * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`. This must be a
29947      *   valid ISO date string (yyyy-MM-dd). You can also use interpolation inside this attribute
29948      *   (e.g. `min="{{minDate | date:'yyyy-MM-dd'}}"`). Note that `min` will also add native HTML5
29949      *   constraint validation.
29950      * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`. This must be
29951      *   a valid ISO date string (yyyy-MM-dd). You can also use interpolation inside this attribute
29952      *   (e.g. `max="{{maxDate | date:'yyyy-MM-dd'}}"`). Note that `max` will also add native HTML5
29953      *   constraint validation.
29954      * @param {(date|string)=} ngMin Sets the `min` validation constraint to the Date / ISO date string
29955      *   the `ngMin` expression evaluates to. Note that it does not set the `min` attribute.
29956      * @param {(date|string)=} ngMax Sets the `max` validation constraint to the Date / ISO date string
29957      *   the `ngMax` expression evaluates to. Note that it does not set the `max` attribute.
29958      * @param {string=} required Sets `required` validation error key if the value is not entered.
29959      * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
29960      *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
29961      *    `required` when you want to data-bind to the `required` attribute.
29962      * @param {string=} ngChange Angular expression to be executed when input changes due to user
29963      *    interaction with the input element.
29964      *
29965      * @example
29966      <example name="date-input-directive" module="dateInputExample">
29967      <file name="index.html">
29968        <script>
29969           angular.module('dateInputExample', [])
29970             .controller('DateController', ['$scope', function($scope) {
29971               $scope.example = {
29972                 value: new Date(2013, 9, 22)
29973               };
29974             }]);
29975        </script>
29976        <form name="myForm" ng-controller="DateController as dateCtrl">
29977           <label for="exampleInput">Pick a date in 2013:</label>
29978           <input type="date" id="exampleInput" name="input" ng-model="example.value"
29979               placeholder="yyyy-MM-dd" min="2013-01-01" max="2013-12-31" required />
29980           <div role="alert">
29981             <span class="error" ng-show="myForm.input.$error.required">
29982                 Required!</span>
29983             <span class="error" ng-show="myForm.input.$error.date">
29984                 Not a valid date!</span>
29985            </div>
29986            <tt>value = {{example.value | date: "yyyy-MM-dd"}}</tt><br/>
29987            <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
29988            <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
29989            <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
29990            <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
29991        </form>
29992      </file>
29993      <file name="protractor.js" type="protractor">
29994         var value = element(by.binding('example.value | date: "yyyy-MM-dd"'));
29995         var valid = element(by.binding('myForm.input.$valid'));
29996         var input = element(by.model('example.value'));
29997
29998         // currently protractor/webdriver does not support
29999         // sending keys to all known HTML5 input controls
30000         // for various browsers (see https://github.com/angular/protractor/issues/562).
30001         function setInput(val) {
30002           // set the value of the element and force validation.
30003           var scr = "var ipt = document.getElementById('exampleInput'); " +
30004           "ipt.value = '" + val + "';" +
30005           "angular.element(ipt).scope().$apply(function(s) { s.myForm[ipt.name].$setViewValue('" + val + "'); });";
30006           browser.executeScript(scr);
30007         }
30008
30009         it('should initialize to model', function() {
30010           expect(value.getText()).toContain('2013-10-22');
30011           expect(valid.getText()).toContain('myForm.input.$valid = true');
30012         });
30013
30014         it('should be invalid if empty', function() {
30015           setInput('');
30016           expect(value.getText()).toEqual('value =');
30017           expect(valid.getText()).toContain('myForm.input.$valid = false');
30018         });
30019
30020         it('should be invalid if over max', function() {
30021           setInput('2015-01-01');
30022           expect(value.getText()).toContain('');
30023           expect(valid.getText()).toContain('myForm.input.$valid = false');
30024         });
30025      </file>
30026      </example>
30027      */
30028   'date': createDateInputType('date', DATE_REGEXP,
30029          createDateParser(DATE_REGEXP, ['yyyy', 'MM', 'dd']),
30030          'yyyy-MM-dd'),
30031
30032    /**
30033     * @ngdoc input
30034     * @name input[datetime-local]
30035     *
30036     * @description
30037     * Input with datetime validation and transformation. In browsers that do not yet support
30038     * the HTML5 date input, a text element will be used. In that case, the text must be entered in a valid ISO-8601
30039     * local datetime format (yyyy-MM-ddTHH:mm:ss), for example: `2010-12-28T14:57:00`.
30040     *
30041     * The model must always be a Date object, otherwise Angular will throw an error.
30042     * Invalid `Date` objects (dates whose `getTime()` is `NaN`) will be rendered as an empty string.
30043     *
30044     * The timezone to be used to read/write the `Date` instance in the model can be defined using
30045     * {@link ng.directive:ngModelOptions ngModelOptions}. By default, this is the timezone of the browser.
30046     *
30047     * @param {string} ngModel Assignable angular expression to data-bind to.
30048     * @param {string=} name Property name of the form under which the control is published.
30049     * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`.
30050     *   This must be a valid ISO datetime format (yyyy-MM-ddTHH:mm:ss). You can also use interpolation
30051     *   inside this attribute (e.g. `min="{{minDatetimeLocal | date:'yyyy-MM-ddTHH:mm:ss'}}"`).
30052     *   Note that `min` will also add native HTML5 constraint validation.
30053     * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`.
30054     *   This must be a valid ISO datetime format (yyyy-MM-ddTHH:mm:ss). You can also use interpolation
30055     *   inside this attribute (e.g. `max="{{maxDatetimeLocal | date:'yyyy-MM-ddTHH:mm:ss'}}"`).
30056     *   Note that `max` will also add native HTML5 constraint validation.
30057     * @param {(date|string)=} ngMin Sets the `min` validation error key to the Date / ISO datetime string
30058     *   the `ngMin` expression evaluates to. Note that it does not set the `min` attribute.
30059     * @param {(date|string)=} ngMax Sets the `max` validation error key to the Date / ISO datetime string
30060     *   the `ngMax` expression evaluates to. Note that it does not set the `max` attribute.
30061     * @param {string=} required Sets `required` validation error key if the value is not entered.
30062     * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
30063     *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
30064     *    `required` when you want to data-bind to the `required` attribute.
30065     * @param {string=} ngChange Angular expression to be executed when input changes due to user
30066     *    interaction with the input element.
30067     *
30068     * @example
30069     <example name="datetimelocal-input-directive" module="dateExample">
30070     <file name="index.html">
30071       <script>
30072         angular.module('dateExample', [])
30073           .controller('DateController', ['$scope', function($scope) {
30074             $scope.example = {
30075               value: new Date(2010, 11, 28, 14, 57)
30076             };
30077           }]);
30078       </script>
30079       <form name="myForm" ng-controller="DateController as dateCtrl">
30080         <label for="exampleInput">Pick a date between in 2013:</label>
30081         <input type="datetime-local" id="exampleInput" name="input" ng-model="example.value"
30082             placeholder="yyyy-MM-ddTHH:mm:ss" min="2001-01-01T00:00:00" max="2013-12-31T00:00:00" required />
30083         <div role="alert">
30084           <span class="error" ng-show="myForm.input.$error.required">
30085               Required!</span>
30086           <span class="error" ng-show="myForm.input.$error.datetimelocal">
30087               Not a valid date!</span>
30088         </div>
30089         <tt>value = {{example.value | date: "yyyy-MM-ddTHH:mm:ss"}}</tt><br/>
30090         <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
30091         <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
30092         <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
30093         <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
30094       </form>
30095     </file>
30096     <file name="protractor.js" type="protractor">
30097       var value = element(by.binding('example.value | date: "yyyy-MM-ddTHH:mm:ss"'));
30098       var valid = element(by.binding('myForm.input.$valid'));
30099       var input = element(by.model('example.value'));
30100
30101       // currently protractor/webdriver does not support
30102       // sending keys to all known HTML5 input controls
30103       // for various browsers (https://github.com/angular/protractor/issues/562).
30104       function setInput(val) {
30105         // set the value of the element and force validation.
30106         var scr = "var ipt = document.getElementById('exampleInput'); " +
30107         "ipt.value = '" + val + "';" +
30108         "angular.element(ipt).scope().$apply(function(s) { s.myForm[ipt.name].$setViewValue('" + val + "'); });";
30109         browser.executeScript(scr);
30110       }
30111
30112       it('should initialize to model', function() {
30113         expect(value.getText()).toContain('2010-12-28T14:57:00');
30114         expect(valid.getText()).toContain('myForm.input.$valid = true');
30115       });
30116
30117       it('should be invalid if empty', function() {
30118         setInput('');
30119         expect(value.getText()).toEqual('value =');
30120         expect(valid.getText()).toContain('myForm.input.$valid = false');
30121       });
30122
30123       it('should be invalid if over max', function() {
30124         setInput('2015-01-01T23:59:00');
30125         expect(value.getText()).toContain('');
30126         expect(valid.getText()).toContain('myForm.input.$valid = false');
30127       });
30128     </file>
30129     </example>
30130     */
30131   'datetime-local': createDateInputType('datetimelocal', DATETIMELOCAL_REGEXP,
30132       createDateParser(DATETIMELOCAL_REGEXP, ['yyyy', 'MM', 'dd', 'HH', 'mm', 'ss', 'sss']),
30133       'yyyy-MM-ddTHH:mm:ss.sss'),
30134
30135   /**
30136    * @ngdoc input
30137    * @name input[time]
30138    *
30139    * @description
30140    * Input with time validation and transformation. In browsers that do not yet support
30141    * the HTML5 date input, a text element will be used. In that case, the text must be entered in a valid ISO-8601
30142    * local time format (HH:mm:ss), for example: `14:57:00`. Model must be a Date object. This binding will always output a
30143    * Date object to the model of January 1, 1970, or local date `new Date(1970, 0, 1, HH, mm, ss)`.
30144    *
30145    * The model must always be a Date object, otherwise Angular will throw an error.
30146    * Invalid `Date` objects (dates whose `getTime()` is `NaN`) will be rendered as an empty string.
30147    *
30148    * The timezone to be used to read/write the `Date` instance in the model can be defined using
30149    * {@link ng.directive:ngModelOptions ngModelOptions}. By default, this is the timezone of the browser.
30150    *
30151    * @param {string} ngModel Assignable angular expression to data-bind to.
30152    * @param {string=} name Property name of the form under which the control is published.
30153    * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`.
30154    *   This must be a valid ISO time format (HH:mm:ss). You can also use interpolation inside this
30155    *   attribute (e.g. `min="{{minTime | date:'HH:mm:ss'}}"`). Note that `min` will also add
30156    *   native HTML5 constraint validation.
30157    * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`.
30158    *   This must be a valid ISO time format (HH:mm:ss). You can also use interpolation inside this
30159    *   attribute (e.g. `max="{{maxTime | date:'HH:mm:ss'}}"`). Note that `max` will also add
30160    *   native HTML5 constraint validation.
30161    * @param {(date|string)=} ngMin Sets the `min` validation constraint to the Date / ISO time string the
30162    *   `ngMin` expression evaluates to. Note that it does not set the `min` attribute.
30163    * @param {(date|string)=} ngMax Sets the `max` validation constraint to the Date / ISO time string the
30164    *   `ngMax` expression evaluates to. Note that it does not set the `max` attribute.
30165    * @param {string=} required Sets `required` validation error key if the value is not entered.
30166    * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
30167    *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
30168    *    `required` when you want to data-bind to the `required` attribute.
30169    * @param {string=} ngChange Angular expression to be executed when input changes due to user
30170    *    interaction with the input element.
30171    *
30172    * @example
30173    <example name="time-input-directive" module="timeExample">
30174    <file name="index.html">
30175      <script>
30176       angular.module('timeExample', [])
30177         .controller('DateController', ['$scope', function($scope) {
30178           $scope.example = {
30179             value: new Date(1970, 0, 1, 14, 57, 0)
30180           };
30181         }]);
30182      </script>
30183      <form name="myForm" ng-controller="DateController as dateCtrl">
30184         <label for="exampleInput">Pick a between 8am and 5pm:</label>
30185         <input type="time" id="exampleInput" name="input" ng-model="example.value"
30186             placeholder="HH:mm:ss" min="08:00:00" max="17:00:00" required />
30187         <div role="alert">
30188           <span class="error" ng-show="myForm.input.$error.required">
30189               Required!</span>
30190           <span class="error" ng-show="myForm.input.$error.time">
30191               Not a valid date!</span>
30192         </div>
30193         <tt>value = {{example.value | date: "HH:mm:ss"}}</tt><br/>
30194         <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
30195         <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
30196         <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
30197         <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
30198      </form>
30199    </file>
30200    <file name="protractor.js" type="protractor">
30201       var value = element(by.binding('example.value | date: "HH:mm:ss"'));
30202       var valid = element(by.binding('myForm.input.$valid'));
30203       var input = element(by.model('example.value'));
30204
30205       // currently protractor/webdriver does not support
30206       // sending keys to all known HTML5 input controls
30207       // for various browsers (https://github.com/angular/protractor/issues/562).
30208       function setInput(val) {
30209         // set the value of the element and force validation.
30210         var scr = "var ipt = document.getElementById('exampleInput'); " +
30211         "ipt.value = '" + val + "';" +
30212         "angular.element(ipt).scope().$apply(function(s) { s.myForm[ipt.name].$setViewValue('" + val + "'); });";
30213         browser.executeScript(scr);
30214       }
30215
30216       it('should initialize to model', function() {
30217         expect(value.getText()).toContain('14:57:00');
30218         expect(valid.getText()).toContain('myForm.input.$valid = true');
30219       });
30220
30221       it('should be invalid if empty', function() {
30222         setInput('');
30223         expect(value.getText()).toEqual('value =');
30224         expect(valid.getText()).toContain('myForm.input.$valid = false');
30225       });
30226
30227       it('should be invalid if over max', function() {
30228         setInput('23:59:00');
30229         expect(value.getText()).toContain('');
30230         expect(valid.getText()).toContain('myForm.input.$valid = false');
30231       });
30232    </file>
30233    </example>
30234    */
30235   'time': createDateInputType('time', TIME_REGEXP,
30236       createDateParser(TIME_REGEXP, ['HH', 'mm', 'ss', 'sss']),
30237      'HH:mm:ss.sss'),
30238
30239    /**
30240     * @ngdoc input
30241     * @name input[week]
30242     *
30243     * @description
30244     * Input with week-of-the-year validation and transformation to Date. In browsers that do not yet support
30245     * the HTML5 week input, a text element will be used. In that case, the text must be entered in a valid ISO-8601
30246     * week format (yyyy-W##), for example: `2013-W02`.
30247     *
30248     * The model must always be a Date object, otherwise Angular will throw an error.
30249     * Invalid `Date` objects (dates whose `getTime()` is `NaN`) will be rendered as an empty string.
30250     *
30251     * The timezone to be used to read/write the `Date` instance in the model can be defined using
30252     * {@link ng.directive:ngModelOptions ngModelOptions}. By default, this is the timezone of the browser.
30253     *
30254     * @param {string} ngModel Assignable angular expression to data-bind to.
30255     * @param {string=} name Property name of the form under which the control is published.
30256     * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`.
30257     *   This must be a valid ISO week format (yyyy-W##). You can also use interpolation inside this
30258     *   attribute (e.g. `min="{{minWeek | date:'yyyy-Www'}}"`). Note that `min` will also add
30259     *   native HTML5 constraint validation.
30260     * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`.
30261     *   This must be a valid ISO week format (yyyy-W##). You can also use interpolation inside this
30262     *   attribute (e.g. `max="{{maxWeek | date:'yyyy-Www'}}"`). Note that `max` will also add
30263     *   native HTML5 constraint validation.
30264     * @param {(date|string)=} ngMin Sets the `min` validation constraint to the Date / ISO week string
30265     *   the `ngMin` expression evaluates to. Note that it does not set the `min` attribute.
30266     * @param {(date|string)=} ngMax Sets the `max` validation constraint to the Date / ISO week string
30267     *   the `ngMax` expression evaluates to. Note that it does not set the `max` attribute.
30268     * @param {string=} required Sets `required` validation error key if the value is not entered.
30269     * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
30270     *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
30271     *    `required` when you want to data-bind to the `required` attribute.
30272     * @param {string=} ngChange Angular expression to be executed when input changes due to user
30273     *    interaction with the input element.
30274     *
30275     * @example
30276     <example name="week-input-directive" module="weekExample">
30277     <file name="index.html">
30278       <script>
30279       angular.module('weekExample', [])
30280         .controller('DateController', ['$scope', function($scope) {
30281           $scope.example = {
30282             value: new Date(2013, 0, 3)
30283           };
30284         }]);
30285       </script>
30286       <form name="myForm" ng-controller="DateController as dateCtrl">
30287         <label>Pick a date between in 2013:
30288           <input id="exampleInput" type="week" name="input" ng-model="example.value"
30289                  placeholder="YYYY-W##" min="2012-W32"
30290                  max="2013-W52" required />
30291         </label>
30292         <div role="alert">
30293           <span class="error" ng-show="myForm.input.$error.required">
30294               Required!</span>
30295           <span class="error" ng-show="myForm.input.$error.week">
30296               Not a valid date!</span>
30297         </div>
30298         <tt>value = {{example.value | date: "yyyy-Www"}}</tt><br/>
30299         <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
30300         <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
30301         <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
30302         <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
30303       </form>
30304     </file>
30305     <file name="protractor.js" type="protractor">
30306       var value = element(by.binding('example.value | date: "yyyy-Www"'));
30307       var valid = element(by.binding('myForm.input.$valid'));
30308       var input = element(by.model('example.value'));
30309
30310       // currently protractor/webdriver does not support
30311       // sending keys to all known HTML5 input controls
30312       // for various browsers (https://github.com/angular/protractor/issues/562).
30313       function setInput(val) {
30314         // set the value of the element and force validation.
30315         var scr = "var ipt = document.getElementById('exampleInput'); " +
30316         "ipt.value = '" + val + "';" +
30317         "angular.element(ipt).scope().$apply(function(s) { s.myForm[ipt.name].$setViewValue('" + val + "'); });";
30318         browser.executeScript(scr);
30319       }
30320
30321       it('should initialize to model', function() {
30322         expect(value.getText()).toContain('2013-W01');
30323         expect(valid.getText()).toContain('myForm.input.$valid = true');
30324       });
30325
30326       it('should be invalid if empty', function() {
30327         setInput('');
30328         expect(value.getText()).toEqual('value =');
30329         expect(valid.getText()).toContain('myForm.input.$valid = false');
30330       });
30331
30332       it('should be invalid if over max', function() {
30333         setInput('2015-W01');
30334         expect(value.getText()).toContain('');
30335         expect(valid.getText()).toContain('myForm.input.$valid = false');
30336       });
30337     </file>
30338     </example>
30339     */
30340   'week': createDateInputType('week', WEEK_REGEXP, weekParser, 'yyyy-Www'),
30341
30342   /**
30343    * @ngdoc input
30344    * @name input[month]
30345    *
30346    * @description
30347    * Input with month validation and transformation. In browsers that do not yet support
30348    * the HTML5 month input, a text element will be used. In that case, the text must be entered in a valid ISO-8601
30349    * month format (yyyy-MM), for example: `2009-01`.
30350    *
30351    * The model must always be a Date object, otherwise Angular will throw an error.
30352    * Invalid `Date` objects (dates whose `getTime()` is `NaN`) will be rendered as an empty string.
30353    * If the model is not set to the first of the month, the next view to model update will set it
30354    * to the first of the month.
30355    *
30356    * The timezone to be used to read/write the `Date` instance in the model can be defined using
30357    * {@link ng.directive:ngModelOptions ngModelOptions}. By default, this is the timezone of the browser.
30358    *
30359    * @param {string} ngModel Assignable angular expression to data-bind to.
30360    * @param {string=} name Property name of the form under which the control is published.
30361    * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`.
30362    *   This must be a valid ISO month format (yyyy-MM). You can also use interpolation inside this
30363    *   attribute (e.g. `min="{{minMonth | date:'yyyy-MM'}}"`). Note that `min` will also add
30364    *   native HTML5 constraint validation.
30365    * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`.
30366    *   This must be a valid ISO month format (yyyy-MM). You can also use interpolation inside this
30367    *   attribute (e.g. `max="{{maxMonth | date:'yyyy-MM'}}"`). Note that `max` will also add
30368    *   native HTML5 constraint validation.
30369    * @param {(date|string)=} ngMin Sets the `min` validation constraint to the Date / ISO week string
30370    *   the `ngMin` expression evaluates to. Note that it does not set the `min` attribute.
30371    * @param {(date|string)=} ngMax Sets the `max` validation constraint to the Date / ISO week string
30372    *   the `ngMax` expression evaluates to. Note that it does not set the `max` attribute.
30373
30374    * @param {string=} required Sets `required` validation error key if the value is not entered.
30375    * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
30376    *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
30377    *    `required` when you want to data-bind to the `required` attribute.
30378    * @param {string=} ngChange Angular expression to be executed when input changes due to user
30379    *    interaction with the input element.
30380    *
30381    * @example
30382    <example name="month-input-directive" module="monthExample">
30383    <file name="index.html">
30384      <script>
30385       angular.module('monthExample', [])
30386         .controller('DateController', ['$scope', function($scope) {
30387           $scope.example = {
30388             value: new Date(2013, 9, 1)
30389           };
30390         }]);
30391      </script>
30392      <form name="myForm" ng-controller="DateController as dateCtrl">
30393        <label for="exampleInput">Pick a month in 2013:</label>
30394        <input id="exampleInput" type="month" name="input" ng-model="example.value"
30395           placeholder="yyyy-MM" min="2013-01" max="2013-12" required />
30396        <div role="alert">
30397          <span class="error" ng-show="myForm.input.$error.required">
30398             Required!</span>
30399          <span class="error" ng-show="myForm.input.$error.month">
30400             Not a valid month!</span>
30401        </div>
30402        <tt>value = {{example.value | date: "yyyy-MM"}}</tt><br/>
30403        <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
30404        <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
30405        <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
30406        <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
30407      </form>
30408    </file>
30409    <file name="protractor.js" type="protractor">
30410       var value = element(by.binding('example.value | date: "yyyy-MM"'));
30411       var valid = element(by.binding('myForm.input.$valid'));
30412       var input = element(by.model('example.value'));
30413
30414       // currently protractor/webdriver does not support
30415       // sending keys to all known HTML5 input controls
30416       // for various browsers (https://github.com/angular/protractor/issues/562).
30417       function setInput(val) {
30418         // set the value of the element and force validation.
30419         var scr = "var ipt = document.getElementById('exampleInput'); " +
30420         "ipt.value = '" + val + "';" +
30421         "angular.element(ipt).scope().$apply(function(s) { s.myForm[ipt.name].$setViewValue('" + val + "'); });";
30422         browser.executeScript(scr);
30423       }
30424
30425       it('should initialize to model', function() {
30426         expect(value.getText()).toContain('2013-10');
30427         expect(valid.getText()).toContain('myForm.input.$valid = true');
30428       });
30429
30430       it('should be invalid if empty', function() {
30431         setInput('');
30432         expect(value.getText()).toEqual('value =');
30433         expect(valid.getText()).toContain('myForm.input.$valid = false');
30434       });
30435
30436       it('should be invalid if over max', function() {
30437         setInput('2015-01');
30438         expect(value.getText()).toContain('');
30439         expect(valid.getText()).toContain('myForm.input.$valid = false');
30440       });
30441    </file>
30442    </example>
30443    */
30444   'month': createDateInputType('month', MONTH_REGEXP,
30445      createDateParser(MONTH_REGEXP, ['yyyy', 'MM']),
30446      'yyyy-MM'),
30447
30448   /**
30449    * @ngdoc input
30450    * @name input[number]
30451    *
30452    * @description
30453    * Text input with number validation and transformation. Sets the `number` validation
30454    * error if not a valid number.
30455    *
30456    * <div class="alert alert-warning">
30457    * The model must always be of type `number` otherwise Angular will throw an error.
30458    * Be aware that a string containing a number is not enough. See the {@link ngModel:numfmt}
30459    * error docs for more information and an example of how to convert your model if necessary.
30460    * </div>
30461    *
30462    * ## Issues with HTML5 constraint validation
30463    *
30464    * In browsers that follow the
30465    * [HTML5 specification](https://html.spec.whatwg.org/multipage/forms.html#number-state-%28type=number%29),
30466    * `input[number]` does not work as expected with {@link ngModelOptions `ngModelOptions.allowInvalid`}.
30467    * If a non-number is entered in the input, the browser will report the value as an empty string,
30468    * which means the view / model values in `ngModel` and subsequently the scope value
30469    * will also be an empty string.
30470    *
30471    *
30472    * @param {string} ngModel Assignable angular expression to data-bind to.
30473    * @param {string=} name Property name of the form under which the control is published.
30474    * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`.
30475    * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`.
30476    * @param {string=} required Sets `required` validation error key if the value is not entered.
30477    * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
30478    *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
30479    *    `required` when you want to data-bind to the `required` attribute.
30480    * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
30481    *    minlength.
30482    * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
30483    *    maxlength. Setting the attribute to a negative or non-numeric value, allows view values of
30484    *    any length.
30485    * @param {string=} pattern Similar to `ngPattern` except that the attribute value is the actual string
30486    *    that contains the regular expression body that will be converted to a regular expression
30487    *    as in the ngPattern directive.
30488    * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel value does not match
30489    *    a RegExp found by evaluating the Angular expression given in the attribute value.
30490    *    If the expression evaluates to a RegExp object, then this is used directly.
30491    *    If the expression evaluates to a string, then it will be converted to a RegExp
30492    *    after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to
30493    *    `new RegExp('^abc$')`.<br />
30494    *    **Note:** Avoid using the `g` flag on the RegExp, as it will cause each successive search to
30495    *    start at the index of the last search's match, thus not taking the whole input value into
30496    *    account.
30497    * @param {string=} ngChange Angular expression to be executed when input changes due to user
30498    *    interaction with the input element.
30499    *
30500    * @example
30501       <example name="number-input-directive" module="numberExample">
30502         <file name="index.html">
30503          <script>
30504            angular.module('numberExample', [])
30505              .controller('ExampleController', ['$scope', function($scope) {
30506                $scope.example = {
30507                  value: 12
30508                };
30509              }]);
30510          </script>
30511          <form name="myForm" ng-controller="ExampleController">
30512            <label>Number:
30513              <input type="number" name="input" ng-model="example.value"
30514                     min="0" max="99" required>
30515           </label>
30516            <div role="alert">
30517              <span class="error" ng-show="myForm.input.$error.required">
30518                Required!</span>
30519              <span class="error" ng-show="myForm.input.$error.number">
30520                Not valid number!</span>
30521            </div>
30522            <tt>value = {{example.value}}</tt><br/>
30523            <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
30524            <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
30525            <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
30526            <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
30527           </form>
30528         </file>
30529         <file name="protractor.js" type="protractor">
30530           var value = element(by.binding('example.value'));
30531           var valid = element(by.binding('myForm.input.$valid'));
30532           var input = element(by.model('example.value'));
30533
30534           it('should initialize to model', function() {
30535             expect(value.getText()).toContain('12');
30536             expect(valid.getText()).toContain('true');
30537           });
30538
30539           it('should be invalid if empty', function() {
30540             input.clear();
30541             input.sendKeys('');
30542             expect(value.getText()).toEqual('value =');
30543             expect(valid.getText()).toContain('false');
30544           });
30545
30546           it('should be invalid if over max', function() {
30547             input.clear();
30548             input.sendKeys('123');
30549             expect(value.getText()).toEqual('value =');
30550             expect(valid.getText()).toContain('false');
30551           });
30552         </file>
30553       </example>
30554    */
30555   'number': numberInputType,
30556
30557
30558   /**
30559    * @ngdoc input
30560    * @name input[url]
30561    *
30562    * @description
30563    * Text input with URL validation. Sets the `url` validation error key if the content is not a
30564    * valid URL.
30565    *
30566    * <div class="alert alert-warning">
30567    * **Note:** `input[url]` uses a regex to validate urls that is derived from the regex
30568    * used in Chromium. If you need stricter validation, you can use `ng-pattern` or modify
30569    * the built-in validators (see the {@link guide/forms Forms guide})
30570    * </div>
30571    *
30572    * @param {string} ngModel Assignable angular expression to data-bind to.
30573    * @param {string=} name Property name of the form under which the control is published.
30574    * @param {string=} required Sets `required` validation error key if the value is not entered.
30575    * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
30576    *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
30577    *    `required` when you want to data-bind to the `required` attribute.
30578    * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
30579    *    minlength.
30580    * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
30581    *    maxlength. Setting the attribute to a negative or non-numeric value, allows view values of
30582    *    any length.
30583    * @param {string=} pattern Similar to `ngPattern` except that the attribute value is the actual string
30584    *    that contains the regular expression body that will be converted to a regular expression
30585    *    as in the ngPattern directive.
30586    * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel value does not match
30587    *    a RegExp found by evaluating the Angular expression given in the attribute value.
30588    *    If the expression evaluates to a RegExp object, then this is used directly.
30589    *    If the expression evaluates to a string, then it will be converted to a RegExp
30590    *    after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to
30591    *    `new RegExp('^abc$')`.<br />
30592    *    **Note:** Avoid using the `g` flag on the RegExp, as it will cause each successive search to
30593    *    start at the index of the last search's match, thus not taking the whole input value into
30594    *    account.
30595    * @param {string=} ngChange Angular expression to be executed when input changes due to user
30596    *    interaction with the input element.
30597    *
30598    * @example
30599       <example name="url-input-directive" module="urlExample">
30600         <file name="index.html">
30601          <script>
30602            angular.module('urlExample', [])
30603              .controller('ExampleController', ['$scope', function($scope) {
30604                $scope.url = {
30605                  text: 'http://google.com'
30606                };
30607              }]);
30608          </script>
30609          <form name="myForm" ng-controller="ExampleController">
30610            <label>URL:
30611              <input type="url" name="input" ng-model="url.text" required>
30612            <label>
30613            <div role="alert">
30614              <span class="error" ng-show="myForm.input.$error.required">
30615                Required!</span>
30616              <span class="error" ng-show="myForm.input.$error.url">
30617                Not valid url!</span>
30618            </div>
30619            <tt>text = {{url.text}}</tt><br/>
30620            <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
30621            <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
30622            <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
30623            <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
30624            <tt>myForm.$error.url = {{!!myForm.$error.url}}</tt><br/>
30625           </form>
30626         </file>
30627         <file name="protractor.js" type="protractor">
30628           var text = element(by.binding('url.text'));
30629           var valid = element(by.binding('myForm.input.$valid'));
30630           var input = element(by.model('url.text'));
30631
30632           it('should initialize to model', function() {
30633             expect(text.getText()).toContain('http://google.com');
30634             expect(valid.getText()).toContain('true');
30635           });
30636
30637           it('should be invalid if empty', function() {
30638             input.clear();
30639             input.sendKeys('');
30640
30641             expect(text.getText()).toEqual('text =');
30642             expect(valid.getText()).toContain('false');
30643           });
30644
30645           it('should be invalid if not url', function() {
30646             input.clear();
30647             input.sendKeys('box');
30648
30649             expect(valid.getText()).toContain('false');
30650           });
30651         </file>
30652       </example>
30653    */
30654   'url': urlInputType,
30655
30656
30657   /**
30658    * @ngdoc input
30659    * @name input[email]
30660    *
30661    * @description
30662    * Text input with email validation. Sets the `email` validation error key if not a valid email
30663    * address.
30664    *
30665    * <div class="alert alert-warning">
30666    * **Note:** `input[email]` uses a regex to validate email addresses that is derived from the regex
30667    * used in Chromium. If you need stricter validation (e.g. requiring a top-level domain), you can
30668    * use `ng-pattern` or modify the built-in validators (see the {@link guide/forms Forms guide})
30669    * </div>
30670    *
30671    * @param {string} ngModel Assignable angular expression to data-bind to.
30672    * @param {string=} name Property name of the form under which the control is published.
30673    * @param {string=} required Sets `required` validation error key if the value is not entered.
30674    * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
30675    *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
30676    *    `required` when you want to data-bind to the `required` attribute.
30677    * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
30678    *    minlength.
30679    * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
30680    *    maxlength. Setting the attribute to a negative or non-numeric value, allows view values of
30681    *    any length.
30682    * @param {string=} pattern Similar to `ngPattern` except that the attribute value is the actual string
30683    *    that contains the regular expression body that will be converted to a regular expression
30684    *    as in the ngPattern directive.
30685    * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel value does not match
30686    *    a RegExp found by evaluating the Angular expression given in the attribute value.
30687    *    If the expression evaluates to a RegExp object, then this is used directly.
30688    *    If the expression evaluates to a string, then it will be converted to a RegExp
30689    *    after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to
30690    *    `new RegExp('^abc$')`.<br />
30691    *    **Note:** Avoid using the `g` flag on the RegExp, as it will cause each successive search to
30692    *    start at the index of the last search's match, thus not taking the whole input value into
30693    *    account.
30694    * @param {string=} ngChange Angular expression to be executed when input changes due to user
30695    *    interaction with the input element.
30696    *
30697    * @example
30698       <example name="email-input-directive" module="emailExample">
30699         <file name="index.html">
30700          <script>
30701            angular.module('emailExample', [])
30702              .controller('ExampleController', ['$scope', function($scope) {
30703                $scope.email = {
30704                  text: 'me@example.com'
30705                };
30706              }]);
30707          </script>
30708            <form name="myForm" ng-controller="ExampleController">
30709              <label>Email:
30710                <input type="email" name="input" ng-model="email.text" required>
30711              </label>
30712              <div role="alert">
30713                <span class="error" ng-show="myForm.input.$error.required">
30714                  Required!</span>
30715                <span class="error" ng-show="myForm.input.$error.email">
30716                  Not valid email!</span>
30717              </div>
30718              <tt>text = {{email.text}}</tt><br/>
30719              <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
30720              <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
30721              <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
30722              <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
30723              <tt>myForm.$error.email = {{!!myForm.$error.email}}</tt><br/>
30724            </form>
30725          </file>
30726         <file name="protractor.js" type="protractor">
30727           var text = element(by.binding('email.text'));
30728           var valid = element(by.binding('myForm.input.$valid'));
30729           var input = element(by.model('email.text'));
30730
30731           it('should initialize to model', function() {
30732             expect(text.getText()).toContain('me@example.com');
30733             expect(valid.getText()).toContain('true');
30734           });
30735
30736           it('should be invalid if empty', function() {
30737             input.clear();
30738             input.sendKeys('');
30739             expect(text.getText()).toEqual('text =');
30740             expect(valid.getText()).toContain('false');
30741           });
30742
30743           it('should be invalid if not email', function() {
30744             input.clear();
30745             input.sendKeys('xxx');
30746
30747             expect(valid.getText()).toContain('false');
30748           });
30749         </file>
30750       </example>
30751    */
30752   'email': emailInputType,
30753
30754
30755   /**
30756    * @ngdoc input
30757    * @name input[radio]
30758    *
30759    * @description
30760    * HTML radio button.
30761    *
30762    * @param {string} ngModel Assignable angular expression to data-bind to.
30763    * @param {string} value The value to which the `ngModel` expression should be set when selected.
30764    *    Note that `value` only supports `string` values, i.e. the scope model needs to be a string,
30765    *    too. Use `ngValue` if you need complex models (`number`, `object`, ...).
30766    * @param {string=} name Property name of the form under which the control is published.
30767    * @param {string=} ngChange Angular expression to be executed when input changes due to user
30768    *    interaction with the input element.
30769    * @param {string} ngValue Angular expression to which `ngModel` will be be set when the radio
30770    *    is selected. Should be used instead of the `value` attribute if you need
30771    *    a non-string `ngModel` (`boolean`, `array`, ...).
30772    *
30773    * @example
30774       <example name="radio-input-directive" module="radioExample">
30775         <file name="index.html">
30776          <script>
30777            angular.module('radioExample', [])
30778              .controller('ExampleController', ['$scope', function($scope) {
30779                $scope.color = {
30780                  name: 'blue'
30781                };
30782                $scope.specialValue = {
30783                  "id": "12345",
30784                  "value": "green"
30785                };
30786              }]);
30787          </script>
30788          <form name="myForm" ng-controller="ExampleController">
30789            <label>
30790              <input type="radio" ng-model="color.name" value="red">
30791              Red
30792            </label><br/>
30793            <label>
30794              <input type="radio" ng-model="color.name" ng-value="specialValue">
30795              Green
30796            </label><br/>
30797            <label>
30798              <input type="radio" ng-model="color.name" value="blue">
30799              Blue
30800            </label><br/>
30801            <tt>color = {{color.name | json}}</tt><br/>
30802           </form>
30803           Note that `ng-value="specialValue"` sets radio item's value to be the value of `$scope.specialValue`.
30804         </file>
30805         <file name="protractor.js" type="protractor">
30806           it('should change state', function() {
30807             var color = element(by.binding('color.name'));
30808
30809             expect(color.getText()).toContain('blue');
30810
30811             element.all(by.model('color.name')).get(0).click();
30812
30813             expect(color.getText()).toContain('red');
30814           });
30815         </file>
30816       </example>
30817    */
30818   'radio': radioInputType,
30819
30820
30821   /**
30822    * @ngdoc input
30823    * @name input[checkbox]
30824    *
30825    * @description
30826    * HTML checkbox.
30827    *
30828    * @param {string} ngModel Assignable angular expression to data-bind to.
30829    * @param {string=} name Property name of the form under which the control is published.
30830    * @param {expression=} ngTrueValue The value to which the expression should be set when selected.
30831    * @param {expression=} ngFalseValue The value to which the expression should be set when not selected.
30832    * @param {string=} ngChange Angular expression to be executed when input changes due to user
30833    *    interaction with the input element.
30834    *
30835    * @example
30836       <example name="checkbox-input-directive" module="checkboxExample">
30837         <file name="index.html">
30838          <script>
30839            angular.module('checkboxExample', [])
30840              .controller('ExampleController', ['$scope', function($scope) {
30841                $scope.checkboxModel = {
30842                 value1 : true,
30843                 value2 : 'YES'
30844               };
30845              }]);
30846          </script>
30847          <form name="myForm" ng-controller="ExampleController">
30848            <label>Value1:
30849              <input type="checkbox" ng-model="checkboxModel.value1">
30850            </label><br/>
30851            <label>Value2:
30852              <input type="checkbox" ng-model="checkboxModel.value2"
30853                     ng-true-value="'YES'" ng-false-value="'NO'">
30854             </label><br/>
30855            <tt>value1 = {{checkboxModel.value1}}</tt><br/>
30856            <tt>value2 = {{checkboxModel.value2}}</tt><br/>
30857           </form>
30858         </file>
30859         <file name="protractor.js" type="protractor">
30860           it('should change state', function() {
30861             var value1 = element(by.binding('checkboxModel.value1'));
30862             var value2 = element(by.binding('checkboxModel.value2'));
30863
30864             expect(value1.getText()).toContain('true');
30865             expect(value2.getText()).toContain('YES');
30866
30867             element(by.model('checkboxModel.value1')).click();
30868             element(by.model('checkboxModel.value2')).click();
30869
30870             expect(value1.getText()).toContain('false');
30871             expect(value2.getText()).toContain('NO');
30872           });
30873         </file>
30874       </example>
30875    */
30876   'checkbox': checkboxInputType,
30877
30878   'hidden': noop,
30879   'button': noop,
30880   'submit': noop,
30881   'reset': noop,
30882   'file': noop
30883 };
30884
30885 function stringBasedInputType(ctrl) {
30886   ctrl.$formatters.push(function(value) {
30887     return ctrl.$isEmpty(value) ? value : value.toString();
30888   });
30889 }
30890
30891 function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {
30892   baseInputType(scope, element, attr, ctrl, $sniffer, $browser);
30893   stringBasedInputType(ctrl);
30894 }
30895
30896 function baseInputType(scope, element, attr, ctrl, $sniffer, $browser) {
30897   var type = lowercase(element[0].type);
30898
30899   // In composition mode, users are still inputing intermediate text buffer,
30900   // hold the listener until composition is done.
30901   // More about composition events: https://developer.mozilla.org/en-US/docs/Web/API/CompositionEvent
30902   if (!$sniffer.android) {
30903     var composing = false;
30904
30905     element.on('compositionstart', function(data) {
30906       composing = true;
30907     });
30908
30909     element.on('compositionend', function() {
30910       composing = false;
30911       listener();
30912     });
30913   }
30914
30915   var listener = function(ev) {
30916     if (timeout) {
30917       $browser.defer.cancel(timeout);
30918       timeout = null;
30919     }
30920     if (composing) return;
30921     var value = element.val(),
30922         event = ev && ev.type;
30923
30924     // By default we will trim the value
30925     // If the attribute ng-trim exists we will avoid trimming
30926     // If input type is 'password', the value is never trimmed
30927     if (type !== 'password' && (!attr.ngTrim || attr.ngTrim !== 'false')) {
30928       value = trim(value);
30929     }
30930
30931     // If a control is suffering from bad input (due to native validators), browsers discard its
30932     // value, so it may be necessary to revalidate (by calling $setViewValue again) even if the
30933     // control's value is the same empty value twice in a row.
30934     if (ctrl.$viewValue !== value || (value === '' && ctrl.$$hasNativeValidators)) {
30935       ctrl.$setViewValue(value, event);
30936     }
30937   };
30938
30939   // if the browser does support "input" event, we are fine - except on IE9 which doesn't fire the
30940   // input event on backspace, delete or cut
30941   if ($sniffer.hasEvent('input')) {
30942     element.on('input', listener);
30943   } else {
30944     var timeout;
30945
30946     var deferListener = function(ev, input, origValue) {
30947       if (!timeout) {
30948         timeout = $browser.defer(function() {
30949           timeout = null;
30950           if (!input || input.value !== origValue) {
30951             listener(ev);
30952           }
30953         });
30954       }
30955     };
30956
30957     element.on('keydown', function(event) {
30958       var key = event.keyCode;
30959
30960       // ignore
30961       //    command            modifiers                   arrows
30962       if (key === 91 || (15 < key && key < 19) || (37 <= key && key <= 40)) return;
30963
30964       deferListener(event, this, this.value);
30965     });
30966
30967     // if user modifies input value using context menu in IE, we need "paste" and "cut" events to catch it
30968     if ($sniffer.hasEvent('paste')) {
30969       element.on('paste cut', deferListener);
30970     }
30971   }
30972
30973   // if user paste into input using mouse on older browser
30974   // or form autocomplete on newer browser, we need "change" event to catch it
30975   element.on('change', listener);
30976
30977   ctrl.$render = function() {
30978     // Workaround for Firefox validation #12102.
30979     var value = ctrl.$isEmpty(ctrl.$viewValue) ? '' : ctrl.$viewValue;
30980     if (element.val() !== value) {
30981       element.val(value);
30982     }
30983   };
30984 }
30985
30986 function weekParser(isoWeek, existingDate) {
30987   if (isDate(isoWeek)) {
30988     return isoWeek;
30989   }
30990
30991   if (isString(isoWeek)) {
30992     WEEK_REGEXP.lastIndex = 0;
30993     var parts = WEEK_REGEXP.exec(isoWeek);
30994     if (parts) {
30995       var year = +parts[1],
30996           week = +parts[2],
30997           hours = 0,
30998           minutes = 0,
30999           seconds = 0,
31000           milliseconds = 0,
31001           firstThurs = getFirstThursdayOfYear(year),
31002           addDays = (week - 1) * 7;
31003
31004       if (existingDate) {
31005         hours = existingDate.getHours();
31006         minutes = existingDate.getMinutes();
31007         seconds = existingDate.getSeconds();
31008         milliseconds = existingDate.getMilliseconds();
31009       }
31010
31011       return new Date(year, 0, firstThurs.getDate() + addDays, hours, minutes, seconds, milliseconds);
31012     }
31013   }
31014
31015   return NaN;
31016 }
31017
31018 function createDateParser(regexp, mapping) {
31019   return function(iso, date) {
31020     var parts, map;
31021
31022     if (isDate(iso)) {
31023       return iso;
31024     }
31025
31026     if (isString(iso)) {
31027       // When a date is JSON'ified to wraps itself inside of an extra
31028       // set of double quotes. This makes the date parsing code unable
31029       // to match the date string and parse it as a date.
31030       if (iso.charAt(0) == '"' && iso.charAt(iso.length - 1) == '"') {
31031         iso = iso.substring(1, iso.length - 1);
31032       }
31033       if (ISO_DATE_REGEXP.test(iso)) {
31034         return new Date(iso);
31035       }
31036       regexp.lastIndex = 0;
31037       parts = regexp.exec(iso);
31038
31039       if (parts) {
31040         parts.shift();
31041         if (date) {
31042           map = {
31043             yyyy: date.getFullYear(),
31044             MM: date.getMonth() + 1,
31045             dd: date.getDate(),
31046             HH: date.getHours(),
31047             mm: date.getMinutes(),
31048             ss: date.getSeconds(),
31049             sss: date.getMilliseconds() / 1000
31050           };
31051         } else {
31052           map = { yyyy: 1970, MM: 1, dd: 1, HH: 0, mm: 0, ss: 0, sss: 0 };
31053         }
31054
31055         forEach(parts, function(part, index) {
31056           if (index < mapping.length) {
31057             map[mapping[index]] = +part;
31058           }
31059         });
31060         return new Date(map.yyyy, map.MM - 1, map.dd, map.HH, map.mm, map.ss || 0, map.sss * 1000 || 0);
31061       }
31062     }
31063
31064     return NaN;
31065   };
31066 }
31067
31068 function createDateInputType(type, regexp, parseDate, format) {
31069   return function dynamicDateInputType(scope, element, attr, ctrl, $sniffer, $browser, $filter) {
31070     badInputChecker(scope, element, attr, ctrl);
31071     baseInputType(scope, element, attr, ctrl, $sniffer, $browser);
31072     var timezone = ctrl && ctrl.$options && ctrl.$options.timezone;
31073     var previousDate;
31074
31075     ctrl.$$parserName = type;
31076     ctrl.$parsers.push(function(value) {
31077       if (ctrl.$isEmpty(value)) return null;
31078       if (regexp.test(value)) {
31079         // Note: We cannot read ctrl.$modelValue, as there might be a different
31080         // parser/formatter in the processing chain so that the model
31081         // contains some different data format!
31082         var parsedDate = parseDate(value, previousDate);
31083         if (timezone) {
31084           parsedDate = convertTimezoneToLocal(parsedDate, timezone);
31085         }
31086         return parsedDate;
31087       }
31088       return undefined;
31089     });
31090
31091     ctrl.$formatters.push(function(value) {
31092       if (value && !isDate(value)) {
31093         throw ngModelMinErr('datefmt', 'Expected `{0}` to be a date', value);
31094       }
31095       if (isValidDate(value)) {
31096         previousDate = value;
31097         if (previousDate && timezone) {
31098           previousDate = convertTimezoneToLocal(previousDate, timezone, true);
31099         }
31100         return $filter('date')(value, format, timezone);
31101       } else {
31102         previousDate = null;
31103         return '';
31104       }
31105     });
31106
31107     if (isDefined(attr.min) || attr.ngMin) {
31108       var minVal;
31109       ctrl.$validators.min = function(value) {
31110         return !isValidDate(value) || isUndefined(minVal) || parseDate(value) >= minVal;
31111       };
31112       attr.$observe('min', function(val) {
31113         minVal = parseObservedDateValue(val);
31114         ctrl.$validate();
31115       });
31116     }
31117
31118     if (isDefined(attr.max) || attr.ngMax) {
31119       var maxVal;
31120       ctrl.$validators.max = function(value) {
31121         return !isValidDate(value) || isUndefined(maxVal) || parseDate(value) <= maxVal;
31122       };
31123       attr.$observe('max', function(val) {
31124         maxVal = parseObservedDateValue(val);
31125         ctrl.$validate();
31126       });
31127     }
31128
31129     function isValidDate(value) {
31130       // Invalid Date: getTime() returns NaN
31131       return value && !(value.getTime && value.getTime() !== value.getTime());
31132     }
31133
31134     function parseObservedDateValue(val) {
31135       return isDefined(val) && !isDate(val) ? parseDate(val) || undefined : val;
31136     }
31137   };
31138 }
31139
31140 function badInputChecker(scope, element, attr, ctrl) {
31141   var node = element[0];
31142   var nativeValidation = ctrl.$$hasNativeValidators = isObject(node.validity);
31143   if (nativeValidation) {
31144     ctrl.$parsers.push(function(value) {
31145       var validity = element.prop(VALIDITY_STATE_PROPERTY) || {};
31146       // Detect bug in FF35 for input[email] (https://bugzilla.mozilla.org/show_bug.cgi?id=1064430):
31147       // - also sets validity.badInput (should only be validity.typeMismatch).
31148       // - see http://www.whatwg.org/specs/web-apps/current-work/multipage/forms.html#e-mail-state-(type=email)
31149       // - can ignore this case as we can still read out the erroneous email...
31150       return validity.badInput && !validity.typeMismatch ? undefined : value;
31151     });
31152   }
31153 }
31154
31155 function numberInputType(scope, element, attr, ctrl, $sniffer, $browser) {
31156   badInputChecker(scope, element, attr, ctrl);
31157   baseInputType(scope, element, attr, ctrl, $sniffer, $browser);
31158
31159   ctrl.$$parserName = 'number';
31160   ctrl.$parsers.push(function(value) {
31161     if (ctrl.$isEmpty(value))      return null;
31162     if (NUMBER_REGEXP.test(value)) return parseFloat(value);
31163     return undefined;
31164   });
31165
31166   ctrl.$formatters.push(function(value) {
31167     if (!ctrl.$isEmpty(value)) {
31168       if (!isNumber(value)) {
31169         throw ngModelMinErr('numfmt', 'Expected `{0}` to be a number', value);
31170       }
31171       value = value.toString();
31172     }
31173     return value;
31174   });
31175
31176   if (isDefined(attr.min) || attr.ngMin) {
31177     var minVal;
31178     ctrl.$validators.min = function(value) {
31179       return ctrl.$isEmpty(value) || isUndefined(minVal) || value >= minVal;
31180     };
31181
31182     attr.$observe('min', function(val) {
31183       if (isDefined(val) && !isNumber(val)) {
31184         val = parseFloat(val, 10);
31185       }
31186       minVal = isNumber(val) && !isNaN(val) ? val : undefined;
31187       // TODO(matsko): implement validateLater to reduce number of validations
31188       ctrl.$validate();
31189     });
31190   }
31191
31192   if (isDefined(attr.max) || attr.ngMax) {
31193     var maxVal;
31194     ctrl.$validators.max = function(value) {
31195       return ctrl.$isEmpty(value) || isUndefined(maxVal) || value <= maxVal;
31196     };
31197
31198     attr.$observe('max', function(val) {
31199       if (isDefined(val) && !isNumber(val)) {
31200         val = parseFloat(val, 10);
31201       }
31202       maxVal = isNumber(val) && !isNaN(val) ? val : undefined;
31203       // TODO(matsko): implement validateLater to reduce number of validations
31204       ctrl.$validate();
31205     });
31206   }
31207 }
31208
31209 function urlInputType(scope, element, attr, ctrl, $sniffer, $browser) {
31210   // Note: no badInputChecker here by purpose as `url` is only a validation
31211   // in browsers, i.e. we can always read out input.value even if it is not valid!
31212   baseInputType(scope, element, attr, ctrl, $sniffer, $browser);
31213   stringBasedInputType(ctrl);
31214
31215   ctrl.$$parserName = 'url';
31216   ctrl.$validators.url = function(modelValue, viewValue) {
31217     var value = modelValue || viewValue;
31218     return ctrl.$isEmpty(value) || URL_REGEXP.test(value);
31219   };
31220 }
31221
31222 function emailInputType(scope, element, attr, ctrl, $sniffer, $browser) {
31223   // Note: no badInputChecker here by purpose as `url` is only a validation
31224   // in browsers, i.e. we can always read out input.value even if it is not valid!
31225   baseInputType(scope, element, attr, ctrl, $sniffer, $browser);
31226   stringBasedInputType(ctrl);
31227
31228   ctrl.$$parserName = 'email';
31229   ctrl.$validators.email = function(modelValue, viewValue) {
31230     var value = modelValue || viewValue;
31231     return ctrl.$isEmpty(value) || EMAIL_REGEXP.test(value);
31232   };
31233 }
31234
31235 function radioInputType(scope, element, attr, ctrl) {
31236   // make the name unique, if not defined
31237   if (isUndefined(attr.name)) {
31238     element.attr('name', nextUid());
31239   }
31240
31241   var listener = function(ev) {
31242     if (element[0].checked) {
31243       ctrl.$setViewValue(attr.value, ev && ev.type);
31244     }
31245   };
31246
31247   element.on('click', listener);
31248
31249   ctrl.$render = function() {
31250     var value = attr.value;
31251     element[0].checked = (value == ctrl.$viewValue);
31252   };
31253
31254   attr.$observe('value', ctrl.$render);
31255 }
31256
31257 function parseConstantExpr($parse, context, name, expression, fallback) {
31258   var parseFn;
31259   if (isDefined(expression)) {
31260     parseFn = $parse(expression);
31261     if (!parseFn.constant) {
31262       throw ngModelMinErr('constexpr', 'Expected constant expression for `{0}`, but saw ' +
31263                                    '`{1}`.', name, expression);
31264     }
31265     return parseFn(context);
31266   }
31267   return fallback;
31268 }
31269
31270 function checkboxInputType(scope, element, attr, ctrl, $sniffer, $browser, $filter, $parse) {
31271   var trueValue = parseConstantExpr($parse, scope, 'ngTrueValue', attr.ngTrueValue, true);
31272   var falseValue = parseConstantExpr($parse, scope, 'ngFalseValue', attr.ngFalseValue, false);
31273
31274   var listener = function(ev) {
31275     ctrl.$setViewValue(element[0].checked, ev && ev.type);
31276   };
31277
31278   element.on('click', listener);
31279
31280   ctrl.$render = function() {
31281     element[0].checked = ctrl.$viewValue;
31282   };
31283
31284   // Override the standard `$isEmpty` because the $viewValue of an empty checkbox is always set to `false`
31285   // This is because of the parser below, which compares the `$modelValue` with `trueValue` to convert
31286   // it to a boolean.
31287   ctrl.$isEmpty = function(value) {
31288     return value === false;
31289   };
31290
31291   ctrl.$formatters.push(function(value) {
31292     return equals(value, trueValue);
31293   });
31294
31295   ctrl.$parsers.push(function(value) {
31296     return value ? trueValue : falseValue;
31297   });
31298 }
31299
31300
31301 /**
31302  * @ngdoc directive
31303  * @name textarea
31304  * @restrict E
31305  *
31306  * @description
31307  * HTML textarea element control with angular data-binding. The data-binding and validation
31308  * properties of this element are exactly the same as those of the
31309  * {@link ng.directive:input input element}.
31310  *
31311  * @param {string} ngModel Assignable angular expression to data-bind to.
31312  * @param {string=} name Property name of the form under which the control is published.
31313  * @param {string=} required Sets `required` validation error key if the value is not entered.
31314  * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
31315  *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
31316  *    `required` when you want to data-bind to the `required` attribute.
31317  * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
31318  *    minlength.
31319  * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
31320  *    maxlength. Setting the attribute to a negative or non-numeric value, allows view values of any
31321  *    length.
31322  * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel value does not match
31323  *    a RegExp found by evaluating the Angular expression given in the attribute value.
31324  *    If the expression evaluates to a RegExp object, then this is used directly.
31325  *    If the expression evaluates to a string, then it will be converted to a RegExp
31326  *    after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to
31327  *    `new RegExp('^abc$')`.<br />
31328  *    **Note:** Avoid using the `g` flag on the RegExp, as it will cause each successive search to
31329  *    start at the index of the last search's match, thus not taking the whole input value into
31330  *    account.
31331  * @param {string=} ngChange Angular expression to be executed when input changes due to user
31332  *    interaction with the input element.
31333  * @param {boolean=} [ngTrim=true] If set to false Angular will not automatically trim the input.
31334  */
31335
31336
31337 /**
31338  * @ngdoc directive
31339  * @name input
31340  * @restrict E
31341  *
31342  * @description
31343  * HTML input element control. When used together with {@link ngModel `ngModel`}, it provides data-binding,
31344  * input state control, and validation.
31345  * Input control follows HTML5 input types and polyfills the HTML5 validation behavior for older browsers.
31346  *
31347  * <div class="alert alert-warning">
31348  * **Note:** Not every feature offered is available for all input types.
31349  * Specifically, data binding and event handling via `ng-model` is unsupported for `input[file]`.
31350  * </div>
31351  *
31352  * @param {string} ngModel Assignable angular expression to data-bind to.
31353  * @param {string=} name Property name of the form under which the control is published.
31354  * @param {string=} required Sets `required` validation error key if the value is not entered.
31355  * @param {boolean=} ngRequired Sets `required` attribute if set to true
31356  * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
31357  *    minlength.
31358  * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
31359  *    maxlength. Setting the attribute to a negative or non-numeric value, allows view values of any
31360  *    length.
31361  * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel value does not match
31362  *    a RegExp found by evaluating the Angular expression given in the attribute value.
31363  *    If the expression evaluates to a RegExp object, then this is used directly.
31364  *    If the expression evaluates to a string, then it will be converted to a RegExp
31365  *    after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to
31366  *    `new RegExp('^abc$')`.<br />
31367  *    **Note:** Avoid using the `g` flag on the RegExp, as it will cause each successive search to
31368  *    start at the index of the last search's match, thus not taking the whole input value into
31369  *    account.
31370  * @param {string=} ngChange Angular expression to be executed when input changes due to user
31371  *    interaction with the input element.
31372  * @param {boolean=} [ngTrim=true] If set to false Angular will not automatically trim the input.
31373  *    This parameter is ignored for input[type=password] controls, which will never trim the
31374  *    input.
31375  *
31376  * @example
31377     <example name="input-directive" module="inputExample">
31378       <file name="index.html">
31379        <script>
31380           angular.module('inputExample', [])
31381             .controller('ExampleController', ['$scope', function($scope) {
31382               $scope.user = {name: 'guest', last: 'visitor'};
31383             }]);
31384        </script>
31385        <div ng-controller="ExampleController">
31386          <form name="myForm">
31387            <label>
31388               User name:
31389               <input type="text" name="userName" ng-model="user.name" required>
31390            </label>
31391            <div role="alert">
31392              <span class="error" ng-show="myForm.userName.$error.required">
31393               Required!</span>
31394            </div>
31395            <label>
31396               Last name:
31397               <input type="text" name="lastName" ng-model="user.last"
31398               ng-minlength="3" ng-maxlength="10">
31399            </label>
31400            <div role="alert">
31401              <span class="error" ng-show="myForm.lastName.$error.minlength">
31402                Too short!</span>
31403              <span class="error" ng-show="myForm.lastName.$error.maxlength">
31404                Too long!</span>
31405            </div>
31406          </form>
31407          <hr>
31408          <tt>user = {{user}}</tt><br/>
31409          <tt>myForm.userName.$valid = {{myForm.userName.$valid}}</tt><br/>
31410          <tt>myForm.userName.$error = {{myForm.userName.$error}}</tt><br/>
31411          <tt>myForm.lastName.$valid = {{myForm.lastName.$valid}}</tt><br/>
31412          <tt>myForm.lastName.$error = {{myForm.lastName.$error}}</tt><br/>
31413          <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
31414          <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
31415          <tt>myForm.$error.minlength = {{!!myForm.$error.minlength}}</tt><br/>
31416          <tt>myForm.$error.maxlength = {{!!myForm.$error.maxlength}}</tt><br/>
31417        </div>
31418       </file>
31419       <file name="protractor.js" type="protractor">
31420         var user = element(by.exactBinding('user'));
31421         var userNameValid = element(by.binding('myForm.userName.$valid'));
31422         var lastNameValid = element(by.binding('myForm.lastName.$valid'));
31423         var lastNameError = element(by.binding('myForm.lastName.$error'));
31424         var formValid = element(by.binding('myForm.$valid'));
31425         var userNameInput = element(by.model('user.name'));
31426         var userLastInput = element(by.model('user.last'));
31427
31428         it('should initialize to model', function() {
31429           expect(user.getText()).toContain('{"name":"guest","last":"visitor"}');
31430           expect(userNameValid.getText()).toContain('true');
31431           expect(formValid.getText()).toContain('true');
31432         });
31433
31434         it('should be invalid if empty when required', function() {
31435           userNameInput.clear();
31436           userNameInput.sendKeys('');
31437
31438           expect(user.getText()).toContain('{"last":"visitor"}');
31439           expect(userNameValid.getText()).toContain('false');
31440           expect(formValid.getText()).toContain('false');
31441         });
31442
31443         it('should be valid if empty when min length is set', function() {
31444           userLastInput.clear();
31445           userLastInput.sendKeys('');
31446
31447           expect(user.getText()).toContain('{"name":"guest","last":""}');
31448           expect(lastNameValid.getText()).toContain('true');
31449           expect(formValid.getText()).toContain('true');
31450         });
31451
31452         it('should be invalid if less than required min length', function() {
31453           userLastInput.clear();
31454           userLastInput.sendKeys('xx');
31455
31456           expect(user.getText()).toContain('{"name":"guest"}');
31457           expect(lastNameValid.getText()).toContain('false');
31458           expect(lastNameError.getText()).toContain('minlength');
31459           expect(formValid.getText()).toContain('false');
31460         });
31461
31462         it('should be invalid if longer than max length', function() {
31463           userLastInput.clear();
31464           userLastInput.sendKeys('some ridiculously long name');
31465
31466           expect(user.getText()).toContain('{"name":"guest"}');
31467           expect(lastNameValid.getText()).toContain('false');
31468           expect(lastNameError.getText()).toContain('maxlength');
31469           expect(formValid.getText()).toContain('false');
31470         });
31471       </file>
31472     </example>
31473  */
31474 var inputDirective = ['$browser', '$sniffer', '$filter', '$parse',
31475     function($browser, $sniffer, $filter, $parse) {
31476   return {
31477     restrict: 'E',
31478     require: ['?ngModel'],
31479     link: {
31480       pre: function(scope, element, attr, ctrls) {
31481         if (ctrls[0]) {
31482           (inputType[lowercase(attr.type)] || inputType.text)(scope, element, attr, ctrls[0], $sniffer,
31483                                                               $browser, $filter, $parse);
31484         }
31485       }
31486     }
31487   };
31488 }];
31489
31490
31491
31492 var CONSTANT_VALUE_REGEXP = /^(true|false|\d+)$/;
31493 /**
31494  * @ngdoc directive
31495  * @name ngValue
31496  *
31497  * @description
31498  * Binds the given expression to the value of `<option>` or {@link input[radio] `input[radio]`},
31499  * so that when the element is selected, the {@link ngModel `ngModel`} of that element is set to
31500  * the bound value.
31501  *
31502  * `ngValue` is useful when dynamically generating lists of radio buttons using
31503  * {@link ngRepeat `ngRepeat`}, as shown below.
31504  *
31505  * Likewise, `ngValue` can be used to generate `<option>` elements for
31506  * the {@link select `select`} element. In that case however, only strings are supported
31507  * for the `value `attribute, so the resulting `ngModel` will always be a string.
31508  * Support for `select` models with non-string values is available via `ngOptions`.
31509  *
31510  * @element input
31511  * @param {string=} ngValue angular expression, whose value will be bound to the `value` attribute
31512  *   of the `input` element
31513  *
31514  * @example
31515     <example name="ngValue-directive" module="valueExample">
31516       <file name="index.html">
31517        <script>
31518           angular.module('valueExample', [])
31519             .controller('ExampleController', ['$scope', function($scope) {
31520               $scope.names = ['pizza', 'unicorns', 'robots'];
31521               $scope.my = { favorite: 'unicorns' };
31522             }]);
31523        </script>
31524         <form ng-controller="ExampleController">
31525           <h2>Which is your favorite?</h2>
31526             <label ng-repeat="name in names" for="{{name}}">
31527               {{name}}
31528               <input type="radio"
31529                      ng-model="my.favorite"
31530                      ng-value="name"
31531                      id="{{name}}"
31532                      name="favorite">
31533             </label>
31534           <div>You chose {{my.favorite}}</div>
31535         </form>
31536       </file>
31537       <file name="protractor.js" type="protractor">
31538         var favorite = element(by.binding('my.favorite'));
31539
31540         it('should initialize to model', function() {
31541           expect(favorite.getText()).toContain('unicorns');
31542         });
31543         it('should bind the values to the inputs', function() {
31544           element.all(by.model('my.favorite')).get(0).click();
31545           expect(favorite.getText()).toContain('pizza');
31546         });
31547       </file>
31548     </example>
31549  */
31550 var ngValueDirective = function() {
31551   return {
31552     restrict: 'A',
31553     priority: 100,
31554     compile: function(tpl, tplAttr) {
31555       if (CONSTANT_VALUE_REGEXP.test(tplAttr.ngValue)) {
31556         return function ngValueConstantLink(scope, elm, attr) {
31557           attr.$set('value', scope.$eval(attr.ngValue));
31558         };
31559       } else {
31560         return function ngValueLink(scope, elm, attr) {
31561           scope.$watch(attr.ngValue, function valueWatchAction(value) {
31562             attr.$set('value', value);
31563           });
31564         };
31565       }
31566     }
31567   };
31568 };
31569
31570 /**
31571  * @ngdoc directive
31572  * @name ngBind
31573  * @restrict AC
31574  *
31575  * @description
31576  * The `ngBind` attribute tells Angular to replace the text content of the specified HTML element
31577  * with the value of a given expression, and to update the text content when the value of that
31578  * expression changes.
31579  *
31580  * Typically, you don't use `ngBind` directly, but instead you use the double curly markup like
31581  * `{{ expression }}` which is similar but less verbose.
31582  *
31583  * It is preferable to use `ngBind` instead of `{{ expression }}` if a template is momentarily
31584  * displayed by the browser in its raw state before Angular compiles it. Since `ngBind` is an
31585  * element attribute, it makes the bindings invisible to the user while the page is loading.
31586  *
31587  * An alternative solution to this problem would be using the
31588  * {@link ng.directive:ngCloak ngCloak} directive.
31589  *
31590  *
31591  * @element ANY
31592  * @param {expression} ngBind {@link guide/expression Expression} to evaluate.
31593  *
31594  * @example
31595  * Enter a name in the Live Preview text box; the greeting below the text box changes instantly.
31596    <example module="bindExample">
31597      <file name="index.html">
31598        <script>
31599          angular.module('bindExample', [])
31600            .controller('ExampleController', ['$scope', function($scope) {
31601              $scope.name = 'Whirled';
31602            }]);
31603        </script>
31604        <div ng-controller="ExampleController">
31605          <label>Enter name: <input type="text" ng-model="name"></label><br>
31606          Hello <span ng-bind="name"></span>!
31607        </div>
31608      </file>
31609      <file name="protractor.js" type="protractor">
31610        it('should check ng-bind', function() {
31611          var nameInput = element(by.model('name'));
31612
31613          expect(element(by.binding('name')).getText()).toBe('Whirled');
31614          nameInput.clear();
31615          nameInput.sendKeys('world');
31616          expect(element(by.binding('name')).getText()).toBe('world');
31617        });
31618      </file>
31619    </example>
31620  */
31621 var ngBindDirective = ['$compile', function($compile) {
31622   return {
31623     restrict: 'AC',
31624     compile: function ngBindCompile(templateElement) {
31625       $compile.$$addBindingClass(templateElement);
31626       return function ngBindLink(scope, element, attr) {
31627         $compile.$$addBindingInfo(element, attr.ngBind);
31628         element = element[0];
31629         scope.$watch(attr.ngBind, function ngBindWatchAction(value) {
31630           element.textContent = isUndefined(value) ? '' : value;
31631         });
31632       };
31633     }
31634   };
31635 }];
31636
31637
31638 /**
31639  * @ngdoc directive
31640  * @name ngBindTemplate
31641  *
31642  * @description
31643  * The `ngBindTemplate` directive specifies that the element
31644  * text content should be replaced with the interpolation of the template
31645  * in the `ngBindTemplate` attribute.
31646  * Unlike `ngBind`, the `ngBindTemplate` can contain multiple `{{` `}}`
31647  * expressions. This directive is needed since some HTML elements
31648  * (such as TITLE and OPTION) cannot contain SPAN elements.
31649  *
31650  * @element ANY
31651  * @param {string} ngBindTemplate template of form
31652  *   <tt>{{</tt> <tt>expression</tt> <tt>}}</tt> to eval.
31653  *
31654  * @example
31655  * Try it here: enter text in text box and watch the greeting change.
31656    <example module="bindExample">
31657      <file name="index.html">
31658        <script>
31659          angular.module('bindExample', [])
31660            .controller('ExampleController', ['$scope', function($scope) {
31661              $scope.salutation = 'Hello';
31662              $scope.name = 'World';
31663            }]);
31664        </script>
31665        <div ng-controller="ExampleController">
31666         <label>Salutation: <input type="text" ng-model="salutation"></label><br>
31667         <label>Name: <input type="text" ng-model="name"></label><br>
31668         <pre ng-bind-template="{{salutation}} {{name}}!"></pre>
31669        </div>
31670      </file>
31671      <file name="protractor.js" type="protractor">
31672        it('should check ng-bind', function() {
31673          var salutationElem = element(by.binding('salutation'));
31674          var salutationInput = element(by.model('salutation'));
31675          var nameInput = element(by.model('name'));
31676
31677          expect(salutationElem.getText()).toBe('Hello World!');
31678
31679          salutationInput.clear();
31680          salutationInput.sendKeys('Greetings');
31681          nameInput.clear();
31682          nameInput.sendKeys('user');
31683
31684          expect(salutationElem.getText()).toBe('Greetings user!');
31685        });
31686      </file>
31687    </example>
31688  */
31689 var ngBindTemplateDirective = ['$interpolate', '$compile', function($interpolate, $compile) {
31690   return {
31691     compile: function ngBindTemplateCompile(templateElement) {
31692       $compile.$$addBindingClass(templateElement);
31693       return function ngBindTemplateLink(scope, element, attr) {
31694         var interpolateFn = $interpolate(element.attr(attr.$attr.ngBindTemplate));
31695         $compile.$$addBindingInfo(element, interpolateFn.expressions);
31696         element = element[0];
31697         attr.$observe('ngBindTemplate', function(value) {
31698           element.textContent = isUndefined(value) ? '' : value;
31699         });
31700       };
31701     }
31702   };
31703 }];
31704
31705
31706 /**
31707  * @ngdoc directive
31708  * @name ngBindHtml
31709  *
31710  * @description
31711  * Evaluates the expression and inserts the resulting HTML into the element in a secure way. By default,
31712  * the resulting HTML content will be sanitized using the {@link ngSanitize.$sanitize $sanitize} service.
31713  * To utilize this functionality, ensure that `$sanitize` is available, for example, by including {@link
31714  * ngSanitize} in your module's dependencies (not in core Angular). In order to use {@link ngSanitize}
31715  * in your module's dependencies, you need to include "angular-sanitize.js" in your application.
31716  *
31717  * You may also bypass sanitization for values you know are safe. To do so, bind to
31718  * an explicitly trusted value via {@link ng.$sce#trustAsHtml $sce.trustAsHtml}.  See the example
31719  * under {@link ng.$sce#show-me-an-example-using-sce- Strict Contextual Escaping (SCE)}.
31720  *
31721  * Note: If a `$sanitize` service is unavailable and the bound value isn't explicitly trusted, you
31722  * will have an exception (instead of an exploit.)
31723  *
31724  * @element ANY
31725  * @param {expression} ngBindHtml {@link guide/expression Expression} to evaluate.
31726  *
31727  * @example
31728
31729    <example module="bindHtmlExample" deps="angular-sanitize.js">
31730      <file name="index.html">
31731        <div ng-controller="ExampleController">
31732         <p ng-bind-html="myHTML"></p>
31733        </div>
31734      </file>
31735
31736      <file name="script.js">
31737        angular.module('bindHtmlExample', ['ngSanitize'])
31738          .controller('ExampleController', ['$scope', function($scope) {
31739            $scope.myHTML =
31740               'I am an <code>HTML</code>string with ' +
31741               '<a href="#">links!</a> and other <em>stuff</em>';
31742          }]);
31743      </file>
31744
31745      <file name="protractor.js" type="protractor">
31746        it('should check ng-bind-html', function() {
31747          expect(element(by.binding('myHTML')).getText()).toBe(
31748              'I am an HTMLstring with links! and other stuff');
31749        });
31750      </file>
31751    </example>
31752  */
31753 var ngBindHtmlDirective = ['$sce', '$parse', '$compile', function($sce, $parse, $compile) {
31754   return {
31755     restrict: 'A',
31756     compile: function ngBindHtmlCompile(tElement, tAttrs) {
31757       var ngBindHtmlGetter = $parse(tAttrs.ngBindHtml);
31758       var ngBindHtmlWatch = $parse(tAttrs.ngBindHtml, function getStringValue(value) {
31759         return (value || '').toString();
31760       });
31761       $compile.$$addBindingClass(tElement);
31762
31763       return function ngBindHtmlLink(scope, element, attr) {
31764         $compile.$$addBindingInfo(element, attr.ngBindHtml);
31765
31766         scope.$watch(ngBindHtmlWatch, function ngBindHtmlWatchAction() {
31767           // we re-evaluate the expr because we want a TrustedValueHolderType
31768           // for $sce, not a string
31769           element.html($sce.getTrustedHtml(ngBindHtmlGetter(scope)) || '');
31770         });
31771       };
31772     }
31773   };
31774 }];
31775
31776 /**
31777  * @ngdoc directive
31778  * @name ngChange
31779  *
31780  * @description
31781  * Evaluate the given expression when the user changes the input.
31782  * The expression is evaluated immediately, unlike the JavaScript onchange event
31783  * which only triggers at the end of a change (usually, when the user leaves the
31784  * form element or presses the return key).
31785  *
31786  * The `ngChange` expression is only evaluated when a change in the input value causes
31787  * a new value to be committed to the model.
31788  *
31789  * It will not be evaluated:
31790  * * if the value returned from the `$parsers` transformation pipeline has not changed
31791  * * if the input has continued to be invalid since the model will stay `null`
31792  * * if the model is changed programmatically and not by a change to the input value
31793  *
31794  *
31795  * Note, this directive requires `ngModel` to be present.
31796  *
31797  * @element input
31798  * @param {expression} ngChange {@link guide/expression Expression} to evaluate upon change
31799  * in input value.
31800  *
31801  * @example
31802  * <example name="ngChange-directive" module="changeExample">
31803  *   <file name="index.html">
31804  *     <script>
31805  *       angular.module('changeExample', [])
31806  *         .controller('ExampleController', ['$scope', function($scope) {
31807  *           $scope.counter = 0;
31808  *           $scope.change = function() {
31809  *             $scope.counter++;
31810  *           };
31811  *         }]);
31812  *     </script>
31813  *     <div ng-controller="ExampleController">
31814  *       <input type="checkbox" ng-model="confirmed" ng-change="change()" id="ng-change-example1" />
31815  *       <input type="checkbox" ng-model="confirmed" id="ng-change-example2" />
31816  *       <label for="ng-change-example2">Confirmed</label><br />
31817  *       <tt>debug = {{confirmed}}</tt><br/>
31818  *       <tt>counter = {{counter}}</tt><br/>
31819  *     </div>
31820  *   </file>
31821  *   <file name="protractor.js" type="protractor">
31822  *     var counter = element(by.binding('counter'));
31823  *     var debug = element(by.binding('confirmed'));
31824  *
31825  *     it('should evaluate the expression if changing from view', function() {
31826  *       expect(counter.getText()).toContain('0');
31827  *
31828  *       element(by.id('ng-change-example1')).click();
31829  *
31830  *       expect(counter.getText()).toContain('1');
31831  *       expect(debug.getText()).toContain('true');
31832  *     });
31833  *
31834  *     it('should not evaluate the expression if changing from model', function() {
31835  *       element(by.id('ng-change-example2')).click();
31836
31837  *       expect(counter.getText()).toContain('0');
31838  *       expect(debug.getText()).toContain('true');
31839  *     });
31840  *   </file>
31841  * </example>
31842  */
31843 var ngChangeDirective = valueFn({
31844   restrict: 'A',
31845   require: 'ngModel',
31846   link: function(scope, element, attr, ctrl) {
31847     ctrl.$viewChangeListeners.push(function() {
31848       scope.$eval(attr.ngChange);
31849     });
31850   }
31851 });
31852
31853 function classDirective(name, selector) {
31854   name = 'ngClass' + name;
31855   return ['$animate', function($animate) {
31856     return {
31857       restrict: 'AC',
31858       link: function(scope, element, attr) {
31859         var oldVal;
31860
31861         scope.$watch(attr[name], ngClassWatchAction, true);
31862
31863         attr.$observe('class', function(value) {
31864           ngClassWatchAction(scope.$eval(attr[name]));
31865         });
31866
31867
31868         if (name !== 'ngClass') {
31869           scope.$watch('$index', function($index, old$index) {
31870             // jshint bitwise: false
31871             var mod = $index & 1;
31872             if (mod !== (old$index & 1)) {
31873               var classes = arrayClasses(scope.$eval(attr[name]));
31874               mod === selector ?
31875                 addClasses(classes) :
31876                 removeClasses(classes);
31877             }
31878           });
31879         }
31880
31881         function addClasses(classes) {
31882           var newClasses = digestClassCounts(classes, 1);
31883           attr.$addClass(newClasses);
31884         }
31885
31886         function removeClasses(classes) {
31887           var newClasses = digestClassCounts(classes, -1);
31888           attr.$removeClass(newClasses);
31889         }
31890
31891         function digestClassCounts(classes, count) {
31892           // Use createMap() to prevent class assumptions involving property
31893           // names in Object.prototype
31894           var classCounts = element.data('$classCounts') || createMap();
31895           var classesToUpdate = [];
31896           forEach(classes, function(className) {
31897             if (count > 0 || classCounts[className]) {
31898               classCounts[className] = (classCounts[className] || 0) + count;
31899               if (classCounts[className] === +(count > 0)) {
31900                 classesToUpdate.push(className);
31901               }
31902             }
31903           });
31904           element.data('$classCounts', classCounts);
31905           return classesToUpdate.join(' ');
31906         }
31907
31908         function updateClasses(oldClasses, newClasses) {
31909           var toAdd = arrayDifference(newClasses, oldClasses);
31910           var toRemove = arrayDifference(oldClasses, newClasses);
31911           toAdd = digestClassCounts(toAdd, 1);
31912           toRemove = digestClassCounts(toRemove, -1);
31913           if (toAdd && toAdd.length) {
31914             $animate.addClass(element, toAdd);
31915           }
31916           if (toRemove && toRemove.length) {
31917             $animate.removeClass(element, toRemove);
31918           }
31919         }
31920
31921         function ngClassWatchAction(newVal) {
31922           if (selector === true || scope.$index % 2 === selector) {
31923             var newClasses = arrayClasses(newVal || []);
31924             if (!oldVal) {
31925               addClasses(newClasses);
31926             } else if (!equals(newVal,oldVal)) {
31927               var oldClasses = arrayClasses(oldVal);
31928               updateClasses(oldClasses, newClasses);
31929             }
31930           }
31931           oldVal = shallowCopy(newVal);
31932         }
31933       }
31934     };
31935
31936     function arrayDifference(tokens1, tokens2) {
31937       var values = [];
31938
31939       outer:
31940       for (var i = 0; i < tokens1.length; i++) {
31941         var token = tokens1[i];
31942         for (var j = 0; j < tokens2.length; j++) {
31943           if (token == tokens2[j]) continue outer;
31944         }
31945         values.push(token);
31946       }
31947       return values;
31948     }
31949
31950     function arrayClasses(classVal) {
31951       var classes = [];
31952       if (isArray(classVal)) {
31953         forEach(classVal, function(v) {
31954           classes = classes.concat(arrayClasses(v));
31955         });
31956         return classes;
31957       } else if (isString(classVal)) {
31958         return classVal.split(' ');
31959       } else if (isObject(classVal)) {
31960         forEach(classVal, function(v, k) {
31961           if (v) {
31962             classes = classes.concat(k.split(' '));
31963           }
31964         });
31965         return classes;
31966       }
31967       return classVal;
31968     }
31969   }];
31970 }
31971
31972 /**
31973  * @ngdoc directive
31974  * @name ngClass
31975  * @restrict AC
31976  *
31977  * @description
31978  * The `ngClass` directive allows you to dynamically set CSS classes on an HTML element by databinding
31979  * an expression that represents all classes to be added.
31980  *
31981  * The directive operates in three different ways, depending on which of three types the expression
31982  * evaluates to:
31983  *
31984  * 1. If the expression evaluates to a string, the string should be one or more space-delimited class
31985  * names.
31986  *
31987  * 2. If the expression evaluates to an object, then for each key-value pair of the
31988  * object with a truthy value the corresponding key is used as a class name.
31989  *
31990  * 3. If the expression evaluates to an array, each element of the array should either be a string as in
31991  * type 1 or an object as in type 2. This means that you can mix strings and objects together in an array
31992  * to give you more control over what CSS classes appear. See the code below for an example of this.
31993  *
31994  *
31995  * The directive won't add duplicate classes if a particular class was already set.
31996  *
31997  * When the expression changes, the previously added classes are removed and only then are the
31998  * new classes added.
31999  *
32000  * @animations
32001  * **add** - happens just before the class is applied to the elements
32002  *
32003  * **remove** - happens just before the class is removed from the element
32004  *
32005  * @element ANY
32006  * @param {expression} ngClass {@link guide/expression Expression} to eval. The result
32007  *   of the evaluation can be a string representing space delimited class
32008  *   names, an array, or a map of class names to boolean values. In the case of a map, the
32009  *   names of the properties whose values are truthy will be added as css classes to the
32010  *   element.
32011  *
32012  * @example Example that demonstrates basic bindings via ngClass directive.
32013    <example>
32014      <file name="index.html">
32015        <p ng-class="{strike: deleted, bold: important, 'has-error': error}">Map Syntax Example</p>
32016        <label>
32017           <input type="checkbox" ng-model="deleted">
32018           deleted (apply "strike" class)
32019        </label><br>
32020        <label>
32021           <input type="checkbox" ng-model="important">
32022           important (apply "bold" class)
32023        </label><br>
32024        <label>
32025           <input type="checkbox" ng-model="error">
32026           error (apply "has-error" class)
32027        </label>
32028        <hr>
32029        <p ng-class="style">Using String Syntax</p>
32030        <input type="text" ng-model="style"
32031               placeholder="Type: bold strike red" aria-label="Type: bold strike red">
32032        <hr>
32033        <p ng-class="[style1, style2, style3]">Using Array Syntax</p>
32034        <input ng-model="style1"
32035               placeholder="Type: bold, strike or red" aria-label="Type: bold, strike or red"><br>
32036        <input ng-model="style2"
32037               placeholder="Type: bold, strike or red" aria-label="Type: bold, strike or red 2"><br>
32038        <input ng-model="style3"
32039               placeholder="Type: bold, strike or red" aria-label="Type: bold, strike or red 3"><br>
32040        <hr>
32041        <p ng-class="[style4, {orange: warning}]">Using Array and Map Syntax</p>
32042        <input ng-model="style4" placeholder="Type: bold, strike" aria-label="Type: bold, strike"><br>
32043        <label><input type="checkbox" ng-model="warning"> warning (apply "orange" class)</label>
32044      </file>
32045      <file name="style.css">
32046        .strike {
32047            text-decoration: line-through;
32048        }
32049        .bold {
32050            font-weight: bold;
32051        }
32052        .red {
32053            color: red;
32054        }
32055        .has-error {
32056            color: red;
32057            background-color: yellow;
32058        }
32059        .orange {
32060            color: orange;
32061        }
32062      </file>
32063      <file name="protractor.js" type="protractor">
32064        var ps = element.all(by.css('p'));
32065
32066        it('should let you toggle the class', function() {
32067
32068          expect(ps.first().getAttribute('class')).not.toMatch(/bold/);
32069          expect(ps.first().getAttribute('class')).not.toMatch(/has-error/);
32070
32071          element(by.model('important')).click();
32072          expect(ps.first().getAttribute('class')).toMatch(/bold/);
32073
32074          element(by.model('error')).click();
32075          expect(ps.first().getAttribute('class')).toMatch(/has-error/);
32076        });
32077
32078        it('should let you toggle string example', function() {
32079          expect(ps.get(1).getAttribute('class')).toBe('');
32080          element(by.model('style')).clear();
32081          element(by.model('style')).sendKeys('red');
32082          expect(ps.get(1).getAttribute('class')).toBe('red');
32083        });
32084
32085        it('array example should have 3 classes', function() {
32086          expect(ps.get(2).getAttribute('class')).toBe('');
32087          element(by.model('style1')).sendKeys('bold');
32088          element(by.model('style2')).sendKeys('strike');
32089          element(by.model('style3')).sendKeys('red');
32090          expect(ps.get(2).getAttribute('class')).toBe('bold strike red');
32091        });
32092
32093        it('array with map example should have 2 classes', function() {
32094          expect(ps.last().getAttribute('class')).toBe('');
32095          element(by.model('style4')).sendKeys('bold');
32096          element(by.model('warning')).click();
32097          expect(ps.last().getAttribute('class')).toBe('bold orange');
32098        });
32099      </file>
32100    </example>
32101
32102    ## Animations
32103
32104    The example below demonstrates how to perform animations using ngClass.
32105
32106    <example module="ngAnimate" deps="angular-animate.js" animations="true">
32107      <file name="index.html">
32108       <input id="setbtn" type="button" value="set" ng-click="myVar='my-class'">
32109       <input id="clearbtn" type="button" value="clear" ng-click="myVar=''">
32110       <br>
32111       <span class="base-class" ng-class="myVar">Sample Text</span>
32112      </file>
32113      <file name="style.css">
32114        .base-class {
32115          transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
32116        }
32117
32118        .base-class.my-class {
32119          color: red;
32120          font-size:3em;
32121        }
32122      </file>
32123      <file name="protractor.js" type="protractor">
32124        it('should check ng-class', function() {
32125          expect(element(by.css('.base-class')).getAttribute('class')).not.
32126            toMatch(/my-class/);
32127
32128          element(by.id('setbtn')).click();
32129
32130          expect(element(by.css('.base-class')).getAttribute('class')).
32131            toMatch(/my-class/);
32132
32133          element(by.id('clearbtn')).click();
32134
32135          expect(element(by.css('.base-class')).getAttribute('class')).not.
32136            toMatch(/my-class/);
32137        });
32138      </file>
32139    </example>
32140
32141
32142    ## ngClass and pre-existing CSS3 Transitions/Animations
32143    The ngClass directive still supports CSS3 Transitions/Animations even if they do not follow the ngAnimate CSS naming structure.
32144    Upon animation ngAnimate will apply supplementary CSS classes to track the start and end of an animation, but this will not hinder
32145    any pre-existing CSS transitions already on the element. To get an idea of what happens during a class-based animation, be sure
32146    to view the step by step details of {@link $animate#addClass $animate.addClass} and
32147    {@link $animate#removeClass $animate.removeClass}.
32148  */
32149 var ngClassDirective = classDirective('', true);
32150
32151 /**
32152  * @ngdoc directive
32153  * @name ngClassOdd
32154  * @restrict AC
32155  *
32156  * @description
32157  * The `ngClassOdd` and `ngClassEven` directives work exactly as
32158  * {@link ng.directive:ngClass ngClass}, except they work in
32159  * conjunction with `ngRepeat` and take effect only on odd (even) rows.
32160  *
32161  * This directive can be applied only within the scope of an
32162  * {@link ng.directive:ngRepeat ngRepeat}.
32163  *
32164  * @element ANY
32165  * @param {expression} ngClassOdd {@link guide/expression Expression} to eval. The result
32166  *   of the evaluation can be a string representing space delimited class names or an array.
32167  *
32168  * @example
32169    <example>
32170      <file name="index.html">
32171         <ol ng-init="names=['John', 'Mary', 'Cate', 'Suz']">
32172           <li ng-repeat="name in names">
32173            <span ng-class-odd="'odd'" ng-class-even="'even'">
32174              {{name}}
32175            </span>
32176           </li>
32177         </ol>
32178      </file>
32179      <file name="style.css">
32180        .odd {
32181          color: red;
32182        }
32183        .even {
32184          color: blue;
32185        }
32186      </file>
32187      <file name="protractor.js" type="protractor">
32188        it('should check ng-class-odd and ng-class-even', function() {
32189          expect(element(by.repeater('name in names').row(0).column('name')).getAttribute('class')).
32190            toMatch(/odd/);
32191          expect(element(by.repeater('name in names').row(1).column('name')).getAttribute('class')).
32192            toMatch(/even/);
32193        });
32194      </file>
32195    </example>
32196  */
32197 var ngClassOddDirective = classDirective('Odd', 0);
32198
32199 /**
32200  * @ngdoc directive
32201  * @name ngClassEven
32202  * @restrict AC
32203  *
32204  * @description
32205  * The `ngClassOdd` and `ngClassEven` directives work exactly as
32206  * {@link ng.directive:ngClass ngClass}, except they work in
32207  * conjunction with `ngRepeat` and take effect only on odd (even) rows.
32208  *
32209  * This directive can be applied only within the scope of an
32210  * {@link ng.directive:ngRepeat ngRepeat}.
32211  *
32212  * @element ANY
32213  * @param {expression} ngClassEven {@link guide/expression Expression} to eval. The
32214  *   result of the evaluation can be a string representing space delimited class names or an array.
32215  *
32216  * @example
32217    <example>
32218      <file name="index.html">
32219         <ol ng-init="names=['John', 'Mary', 'Cate', 'Suz']">
32220           <li ng-repeat="name in names">
32221            <span ng-class-odd="'odd'" ng-class-even="'even'">
32222              {{name}} &nbsp; &nbsp; &nbsp;
32223            </span>
32224           </li>
32225         </ol>
32226      </file>
32227      <file name="style.css">
32228        .odd {
32229          color: red;
32230        }
32231        .even {
32232          color: blue;
32233        }
32234      </file>
32235      <file name="protractor.js" type="protractor">
32236        it('should check ng-class-odd and ng-class-even', function() {
32237          expect(element(by.repeater('name in names').row(0).column('name')).getAttribute('class')).
32238            toMatch(/odd/);
32239          expect(element(by.repeater('name in names').row(1).column('name')).getAttribute('class')).
32240            toMatch(/even/);
32241        });
32242      </file>
32243    </example>
32244  */
32245 var ngClassEvenDirective = classDirective('Even', 1);
32246
32247 /**
32248  * @ngdoc directive
32249  * @name ngCloak
32250  * @restrict AC
32251  *
32252  * @description
32253  * The `ngCloak` directive is used to prevent the Angular html template from being briefly
32254  * displayed by the browser in its raw (uncompiled) form while your application is loading. Use this
32255  * directive to avoid the undesirable flicker effect caused by the html template display.
32256  *
32257  * The directive can be applied to the `<body>` element, but the preferred usage is to apply
32258  * multiple `ngCloak` directives to small portions of the page to permit progressive rendering
32259  * of the browser view.
32260  *
32261  * `ngCloak` works in cooperation with the following css rule embedded within `angular.js` and
32262  * `angular.min.js`.
32263  * For CSP mode please add `angular-csp.css` to your html file (see {@link ng.directive:ngCsp ngCsp}).
32264  *
32265  * ```css
32266  * [ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak {
32267  *   display: none !important;
32268  * }
32269  * ```
32270  *
32271  * When this css rule is loaded by the browser, all html elements (including their children) that
32272  * are tagged with the `ngCloak` directive are hidden. When Angular encounters this directive
32273  * during the compilation of the template it deletes the `ngCloak` element attribute, making
32274  * the compiled element visible.
32275  *
32276  * For the best result, the `angular.js` script must be loaded in the head section of the html
32277  * document; alternatively, the css rule above must be included in the external stylesheet of the
32278  * application.
32279  *
32280  * @element ANY
32281  *
32282  * @example
32283    <example>
32284      <file name="index.html">
32285         <div id="template1" ng-cloak>{{ 'hello' }}</div>
32286         <div id="template2" class="ng-cloak">{{ 'world' }}</div>
32287      </file>
32288      <file name="protractor.js" type="protractor">
32289        it('should remove the template directive and css class', function() {
32290          expect($('#template1').getAttribute('ng-cloak')).
32291            toBeNull();
32292          expect($('#template2').getAttribute('ng-cloak')).
32293            toBeNull();
32294        });
32295      </file>
32296    </example>
32297  *
32298  */
32299 var ngCloakDirective = ngDirective({
32300   compile: function(element, attr) {
32301     attr.$set('ngCloak', undefined);
32302     element.removeClass('ng-cloak');
32303   }
32304 });
32305
32306 /**
32307  * @ngdoc directive
32308  * @name ngController
32309  *
32310  * @description
32311  * The `ngController` directive attaches a controller class to the view. This is a key aspect of how angular
32312  * supports the principles behind the Model-View-Controller design pattern.
32313  *
32314  * MVC components in angular:
32315  *
32316  * * Model — Models are the properties of a scope; scopes are attached to the DOM where scope properties
32317  *   are accessed through bindings.
32318  * * View — The template (HTML with data bindings) that is rendered into the View.
32319  * * Controller — The `ngController` directive specifies a Controller class; the class contains business
32320  *   logic behind the application to decorate the scope with functions and values
32321  *
32322  * Note that you can also attach controllers to the DOM by declaring it in a route definition
32323  * via the {@link ngRoute.$route $route} service. A common mistake is to declare the controller
32324  * again using `ng-controller` in the template itself.  This will cause the controller to be attached
32325  * and executed twice.
32326  *
32327  * @element ANY
32328  * @scope
32329  * @priority 500
32330  * @param {expression} ngController Name of a constructor function registered with the current
32331  * {@link ng.$controllerProvider $controllerProvider} or an {@link guide/expression expression}
32332  * that on the current scope evaluates to a constructor function.
32333  *
32334  * The controller instance can be published into a scope property by specifying
32335  * `ng-controller="as propertyName"`.
32336  *
32337  * If the current `$controllerProvider` is configured to use globals (via
32338  * {@link ng.$controllerProvider#allowGlobals `$controllerProvider.allowGlobals()` }), this may
32339  * also be the name of a globally accessible constructor function (not recommended).
32340  *
32341  * @example
32342  * Here is a simple form for editing user contact information. Adding, removing, clearing, and
32343  * greeting are methods declared on the controller (see source tab). These methods can
32344  * easily be called from the angular markup. Any changes to the data are automatically reflected
32345  * in the View without the need for a manual update.
32346  *
32347  * Two different declaration styles are included below:
32348  *
32349  * * one binds methods and properties directly onto the controller using `this`:
32350  * `ng-controller="SettingsController1 as settings"`
32351  * * one injects `$scope` into the controller:
32352  * `ng-controller="SettingsController2"`
32353  *
32354  * The second option is more common in the Angular community, and is generally used in boilerplates
32355  * and in this guide. However, there are advantages to binding properties directly to the controller
32356  * and avoiding scope.
32357  *
32358  * * Using `controller as` makes it obvious which controller you are accessing in the template when
32359  * multiple controllers apply to an element.
32360  * * If you are writing your controllers as classes you have easier access to the properties and
32361  * methods, which will appear on the scope, from inside the controller code.
32362  * * Since there is always a `.` in the bindings, you don't have to worry about prototypal
32363  * inheritance masking primitives.
32364  *
32365  * This example demonstrates the `controller as` syntax.
32366  *
32367  * <example name="ngControllerAs" module="controllerAsExample">
32368  *   <file name="index.html">
32369  *    <div id="ctrl-as-exmpl" ng-controller="SettingsController1 as settings">
32370  *      <label>Name: <input type="text" ng-model="settings.name"/></label>
32371  *      <button ng-click="settings.greet()">greet</button><br/>
32372  *      Contact:
32373  *      <ul>
32374  *        <li ng-repeat="contact in settings.contacts">
32375  *          <select ng-model="contact.type" aria-label="Contact method" id="select_{{$index}}">
32376  *             <option>phone</option>
32377  *             <option>email</option>
32378  *          </select>
32379  *          <input type="text" ng-model="contact.value" aria-labelledby="select_{{$index}}" />
32380  *          <button ng-click="settings.clearContact(contact)">clear</button>
32381  *          <button ng-click="settings.removeContact(contact)" aria-label="Remove">X</button>
32382  *        </li>
32383  *        <li><button ng-click="settings.addContact()">add</button></li>
32384  *     </ul>
32385  *    </div>
32386  *   </file>
32387  *   <file name="app.js">
32388  *    angular.module('controllerAsExample', [])
32389  *      .controller('SettingsController1', SettingsController1);
32390  *
32391  *    function SettingsController1() {
32392  *      this.name = "John Smith";
32393  *      this.contacts = [
32394  *        {type: 'phone', value: '408 555 1212'},
32395  *        {type: 'email', value: 'john.smith@example.org'} ];
32396  *    }
32397  *
32398  *    SettingsController1.prototype.greet = function() {
32399  *      alert(this.name);
32400  *    };
32401  *
32402  *    SettingsController1.prototype.addContact = function() {
32403  *      this.contacts.push({type: 'email', value: 'yourname@example.org'});
32404  *    };
32405  *
32406  *    SettingsController1.prototype.removeContact = function(contactToRemove) {
32407  *     var index = this.contacts.indexOf(contactToRemove);
32408  *      this.contacts.splice(index, 1);
32409  *    };
32410  *
32411  *    SettingsController1.prototype.clearContact = function(contact) {
32412  *      contact.type = 'phone';
32413  *      contact.value = '';
32414  *    };
32415  *   </file>
32416  *   <file name="protractor.js" type="protractor">
32417  *     it('should check controller as', function() {
32418  *       var container = element(by.id('ctrl-as-exmpl'));
32419  *         expect(container.element(by.model('settings.name'))
32420  *           .getAttribute('value')).toBe('John Smith');
32421  *
32422  *       var firstRepeat =
32423  *           container.element(by.repeater('contact in settings.contacts').row(0));
32424  *       var secondRepeat =
32425  *           container.element(by.repeater('contact in settings.contacts').row(1));
32426  *
32427  *       expect(firstRepeat.element(by.model('contact.value')).getAttribute('value'))
32428  *           .toBe('408 555 1212');
32429  *
32430  *       expect(secondRepeat.element(by.model('contact.value')).getAttribute('value'))
32431  *           .toBe('john.smith@example.org');
32432  *
32433  *       firstRepeat.element(by.buttonText('clear')).click();
32434  *
32435  *       expect(firstRepeat.element(by.model('contact.value')).getAttribute('value'))
32436  *           .toBe('');
32437  *
32438  *       container.element(by.buttonText('add')).click();
32439  *
32440  *       expect(container.element(by.repeater('contact in settings.contacts').row(2))
32441  *           .element(by.model('contact.value'))
32442  *           .getAttribute('value'))
32443  *           .toBe('yourname@example.org');
32444  *     });
32445  *   </file>
32446  * </example>
32447  *
32448  * This example demonstrates the "attach to `$scope`" style of controller.
32449  *
32450  * <example name="ngController" module="controllerExample">
32451  *  <file name="index.html">
32452  *   <div id="ctrl-exmpl" ng-controller="SettingsController2">
32453  *     <label>Name: <input type="text" ng-model="name"/></label>
32454  *     <button ng-click="greet()">greet</button><br/>
32455  *     Contact:
32456  *     <ul>
32457  *       <li ng-repeat="contact in contacts">
32458  *         <select ng-model="contact.type" id="select_{{$index}}">
32459  *            <option>phone</option>
32460  *            <option>email</option>
32461  *         </select>
32462  *         <input type="text" ng-model="contact.value" aria-labelledby="select_{{$index}}" />
32463  *         <button ng-click="clearContact(contact)">clear</button>
32464  *         <button ng-click="removeContact(contact)">X</button>
32465  *       </li>
32466  *       <li>[ <button ng-click="addContact()">add</button> ]</li>
32467  *    </ul>
32468  *   </div>
32469  *  </file>
32470  *  <file name="app.js">
32471  *   angular.module('controllerExample', [])
32472  *     .controller('SettingsController2', ['$scope', SettingsController2]);
32473  *
32474  *   function SettingsController2($scope) {
32475  *     $scope.name = "John Smith";
32476  *     $scope.contacts = [
32477  *       {type:'phone', value:'408 555 1212'},
32478  *       {type:'email', value:'john.smith@example.org'} ];
32479  *
32480  *     $scope.greet = function() {
32481  *       alert($scope.name);
32482  *     };
32483  *
32484  *     $scope.addContact = function() {
32485  *       $scope.contacts.push({type:'email', value:'yourname@example.org'});
32486  *     };
32487  *
32488  *     $scope.removeContact = function(contactToRemove) {
32489  *       var index = $scope.contacts.indexOf(contactToRemove);
32490  *       $scope.contacts.splice(index, 1);
32491  *     };
32492  *
32493  *     $scope.clearContact = function(contact) {
32494  *       contact.type = 'phone';
32495  *       contact.value = '';
32496  *     };
32497  *   }
32498  *  </file>
32499  *  <file name="protractor.js" type="protractor">
32500  *    it('should check controller', function() {
32501  *      var container = element(by.id('ctrl-exmpl'));
32502  *
32503  *      expect(container.element(by.model('name'))
32504  *          .getAttribute('value')).toBe('John Smith');
32505  *
32506  *      var firstRepeat =
32507  *          container.element(by.repeater('contact in contacts').row(0));
32508  *      var secondRepeat =
32509  *          container.element(by.repeater('contact in contacts').row(1));
32510  *
32511  *      expect(firstRepeat.element(by.model('contact.value')).getAttribute('value'))
32512  *          .toBe('408 555 1212');
32513  *      expect(secondRepeat.element(by.model('contact.value')).getAttribute('value'))
32514  *          .toBe('john.smith@example.org');
32515  *
32516  *      firstRepeat.element(by.buttonText('clear')).click();
32517  *
32518  *      expect(firstRepeat.element(by.model('contact.value')).getAttribute('value'))
32519  *          .toBe('');
32520  *
32521  *      container.element(by.buttonText('add')).click();
32522  *
32523  *      expect(container.element(by.repeater('contact in contacts').row(2))
32524  *          .element(by.model('contact.value'))
32525  *          .getAttribute('value'))
32526  *          .toBe('yourname@example.org');
32527  *    });
32528  *  </file>
32529  *</example>
32530
32531  */
32532 var ngControllerDirective = [function() {
32533   return {
32534     restrict: 'A',
32535     scope: true,
32536     controller: '@',
32537     priority: 500
32538   };
32539 }];
32540
32541 /**
32542  * @ngdoc directive
32543  * @name ngCsp
32544  *
32545  * @element html
32546  * @description
32547  *
32548  * Angular has some features that can break certain
32549  * [CSP (Content Security Policy)](https://developer.mozilla.org/en/Security/CSP) rules.
32550  *
32551  * If you intend to implement these rules then you must tell Angular not to use these features.
32552  *
32553  * This is necessary when developing things like Google Chrome Extensions or Universal Windows Apps.
32554  *
32555  *
32556  * The following rules affect Angular:
32557  *
32558  * * `unsafe-eval`: this rule forbids apps to use `eval` or `Function(string)` generated functions
32559  * (among other things). Angular makes use of this in the {@link $parse} service to provide a 30%
32560  * increase in the speed of evaluating Angular expressions.
32561  *
32562  * * `unsafe-inline`: this rule forbids apps from inject custom styles into the document. Angular
32563  * makes use of this to include some CSS rules (e.g. {@link ngCloak} and {@link ngHide}).
32564  * To make these directives work when a CSP rule is blocking inline styles, you must link to the
32565  * `angular-csp.css` in your HTML manually.
32566  *
32567  * If you do not provide `ngCsp` then Angular tries to autodetect if CSP is blocking unsafe-eval
32568  * and automatically deactivates this feature in the {@link $parse} service. This autodetection,
32569  * however, triggers a CSP error to be logged in the console:
32570  *
32571  * ```
32572  * Refused to evaluate a string as JavaScript because 'unsafe-eval' is not an allowed source of
32573  * script in the following Content Security Policy directive: "default-src 'self'". Note that
32574  * 'script-src' was not explicitly set, so 'default-src' is used as a fallback.
32575  * ```
32576  *
32577  * This error is harmless but annoying. To prevent the error from showing up, put the `ngCsp`
32578  * directive on an element of the HTML document that appears before the `<script>` tag that loads
32579  * the `angular.js` file.
32580  *
32581  * *Note: This directive is only available in the `ng-csp` and `data-ng-csp` attribute form.*
32582  *
32583  * You can specify which of the CSP related Angular features should be deactivated by providing
32584  * a value for the `ng-csp` attribute. The options are as follows:
32585  *
32586  * * no-inline-style: this stops Angular from injecting CSS styles into the DOM
32587  *
32588  * * no-unsafe-eval: this stops Angular from optimising $parse with unsafe eval of strings
32589  *
32590  * You can use these values in the following combinations:
32591  *
32592  *
32593  * * No declaration means that Angular will assume that you can do inline styles, but it will do
32594  * a runtime check for unsafe-eval. E.g. `<body>`. This is backwardly compatible with previous versions
32595  * of Angular.
32596  *
32597  * * A simple `ng-csp` (or `data-ng-csp`) attribute will tell Angular to deactivate both inline
32598  * styles and unsafe eval. E.g. `<body ng-csp>`. This is backwardly compatible with previous versions
32599  * of Angular.
32600  *
32601  * * Specifying only `no-unsafe-eval` tells Angular that we must not use eval, but that we can inject
32602  * inline styles. E.g. `<body ng-csp="no-unsafe-eval">`.
32603  *
32604  * * Specifying only `no-inline-style` tells Angular that we must not inject styles, but that we can
32605  * run eval - no automcatic check for unsafe eval will occur. E.g. `<body ng-csp="no-inline-style">`
32606  *
32607  * * Specifying both `no-unsafe-eval` and `no-inline-style` tells Angular that we must not inject
32608  * styles nor use eval, which is the same as an empty: ng-csp.
32609  * E.g.`<body ng-csp="no-inline-style;no-unsafe-eval">`
32610  *
32611  * @example
32612  * This example shows how to apply the `ngCsp` directive to the `html` tag.
32613    ```html
32614      <!doctype html>
32615      <html ng-app ng-csp>
32616      ...
32617      ...
32618      </html>
32619    ```
32620   * @example
32621       // Note: the suffix `.csp` in the example name triggers
32622       // csp mode in our http server!
32623       <example name="example.csp" module="cspExample" ng-csp="true">
32624         <file name="index.html">
32625           <div ng-controller="MainController as ctrl">
32626             <div>
32627               <button ng-click="ctrl.inc()" id="inc">Increment</button>
32628               <span id="counter">
32629                 {{ctrl.counter}}
32630               </span>
32631             </div>
32632
32633             <div>
32634               <button ng-click="ctrl.evil()" id="evil">Evil</button>
32635               <span id="evilError">
32636                 {{ctrl.evilError}}
32637               </span>
32638             </div>
32639           </div>
32640         </file>
32641         <file name="script.js">
32642            angular.module('cspExample', [])
32643              .controller('MainController', function() {
32644                 this.counter = 0;
32645                 this.inc = function() {
32646                   this.counter++;
32647                 };
32648                 this.evil = function() {
32649                   // jshint evil:true
32650                   try {
32651                     eval('1+2');
32652                   } catch (e) {
32653                     this.evilError = e.message;
32654                   }
32655                 };
32656               });
32657         </file>
32658         <file name="protractor.js" type="protractor">
32659           var util, webdriver;
32660
32661           var incBtn = element(by.id('inc'));
32662           var counter = element(by.id('counter'));
32663           var evilBtn = element(by.id('evil'));
32664           var evilError = element(by.id('evilError'));
32665
32666           function getAndClearSevereErrors() {
32667             return browser.manage().logs().get('browser').then(function(browserLog) {
32668               return browserLog.filter(function(logEntry) {
32669                 return logEntry.level.value > webdriver.logging.Level.WARNING.value;
32670               });
32671             });
32672           }
32673
32674           function clearErrors() {
32675             getAndClearSevereErrors();
32676           }
32677
32678           function expectNoErrors() {
32679             getAndClearSevereErrors().then(function(filteredLog) {
32680               expect(filteredLog.length).toEqual(0);
32681               if (filteredLog.length) {
32682                 console.log('browser console errors: ' + util.inspect(filteredLog));
32683               }
32684             });
32685           }
32686
32687           function expectError(regex) {
32688             getAndClearSevereErrors().then(function(filteredLog) {
32689               var found = false;
32690               filteredLog.forEach(function(log) {
32691                 if (log.message.match(regex)) {
32692                   found = true;
32693                 }
32694               });
32695               if (!found) {
32696                 throw new Error('expected an error that matches ' + regex);
32697               }
32698             });
32699           }
32700
32701           beforeEach(function() {
32702             util = require('util');
32703             webdriver = require('protractor/node_modules/selenium-webdriver');
32704           });
32705
32706           // For now, we only test on Chrome,
32707           // as Safari does not load the page with Protractor's injected scripts,
32708           // and Firefox webdriver always disables content security policy (#6358)
32709           if (browser.params.browser !== 'chrome') {
32710             return;
32711           }
32712
32713           it('should not report errors when the page is loaded', function() {
32714             // clear errors so we are not dependent on previous tests
32715             clearErrors();
32716             // Need to reload the page as the page is already loaded when
32717             // we come here
32718             browser.driver.getCurrentUrl().then(function(url) {
32719               browser.get(url);
32720             });
32721             expectNoErrors();
32722           });
32723
32724           it('should evaluate expressions', function() {
32725             expect(counter.getText()).toEqual('0');
32726             incBtn.click();
32727             expect(counter.getText()).toEqual('1');
32728             expectNoErrors();
32729           });
32730
32731           it('should throw and report an error when using "eval"', function() {
32732             evilBtn.click();
32733             expect(evilError.getText()).toMatch(/Content Security Policy/);
32734             expectError(/Content Security Policy/);
32735           });
32736         </file>
32737       </example>
32738   */
32739
32740 // ngCsp is not implemented as a proper directive any more, because we need it be processed while we
32741 // bootstrap the system (before $parse is instantiated), for this reason we just have
32742 // the csp() fn that looks for the `ng-csp` attribute anywhere in the current doc
32743
32744 /**
32745  * @ngdoc directive
32746  * @name ngClick
32747  *
32748  * @description
32749  * The ngClick directive allows you to specify custom behavior when
32750  * an element is clicked.
32751  *
32752  * @element ANY
32753  * @priority 0
32754  * @param {expression} ngClick {@link guide/expression Expression} to evaluate upon
32755  * click. ({@link guide/expression#-event- Event object is available as `$event`})
32756  *
32757  * @example
32758    <example>
32759      <file name="index.html">
32760       <button ng-click="count = count + 1" ng-init="count=0">
32761         Increment
32762       </button>
32763       <span>
32764         count: {{count}}
32765       </span>
32766      </file>
32767      <file name="protractor.js" type="protractor">
32768        it('should check ng-click', function() {
32769          expect(element(by.binding('count')).getText()).toMatch('0');
32770          element(by.css('button')).click();
32771          expect(element(by.binding('count')).getText()).toMatch('1');
32772        });
32773      </file>
32774    </example>
32775  */
32776 /*
32777  * A collection of directives that allows creation of custom event handlers that are defined as
32778  * angular expressions and are compiled and executed within the current scope.
32779  */
32780 var ngEventDirectives = {};
32781
32782 // For events that might fire synchronously during DOM manipulation
32783 // we need to execute their event handlers asynchronously using $evalAsync,
32784 // so that they are not executed in an inconsistent state.
32785 var forceAsyncEvents = {
32786   'blur': true,
32787   'focus': true
32788 };
32789 forEach(
32790   'click dblclick mousedown mouseup mouseover mouseout mousemove mouseenter mouseleave keydown keyup keypress submit focus blur copy cut paste'.split(' '),
32791   function(eventName) {
32792     var directiveName = directiveNormalize('ng-' + eventName);
32793     ngEventDirectives[directiveName] = ['$parse', '$rootScope', function($parse, $rootScope) {
32794       return {
32795         restrict: 'A',
32796         compile: function($element, attr) {
32797           // We expose the powerful $event object on the scope that provides access to the Window,
32798           // etc. that isn't protected by the fast paths in $parse.  We explicitly request better
32799           // checks at the cost of speed since event handler expressions are not executed as
32800           // frequently as regular change detection.
32801           var fn = $parse(attr[directiveName], /* interceptorFn */ null, /* expensiveChecks */ true);
32802           return function ngEventHandler(scope, element) {
32803             element.on(eventName, function(event) {
32804               var callback = function() {
32805                 fn(scope, {$event:event});
32806               };
32807               if (forceAsyncEvents[eventName] && $rootScope.$$phase) {
32808                 scope.$evalAsync(callback);
32809               } else {
32810                 scope.$apply(callback);
32811               }
32812             });
32813           };
32814         }
32815       };
32816     }];
32817   }
32818 );
32819
32820 /**
32821  * @ngdoc directive
32822  * @name ngDblclick
32823  *
32824  * @description
32825  * The `ngDblclick` directive allows you to specify custom behavior on a dblclick event.
32826  *
32827  * @element ANY
32828  * @priority 0
32829  * @param {expression} ngDblclick {@link guide/expression Expression} to evaluate upon
32830  * a dblclick. (The Event object is available as `$event`)
32831  *
32832  * @example
32833    <example>
32834      <file name="index.html">
32835       <button ng-dblclick="count = count + 1" ng-init="count=0">
32836         Increment (on double click)
32837       </button>
32838       count: {{count}}
32839      </file>
32840    </example>
32841  */
32842
32843
32844 /**
32845  * @ngdoc directive
32846  * @name ngMousedown
32847  *
32848  * @description
32849  * The ngMousedown directive allows you to specify custom behavior on mousedown event.
32850  *
32851  * @element ANY
32852  * @priority 0
32853  * @param {expression} ngMousedown {@link guide/expression Expression} to evaluate upon
32854  * mousedown. ({@link guide/expression#-event- Event object is available as `$event`})
32855  *
32856  * @example
32857    <example>
32858      <file name="index.html">
32859       <button ng-mousedown="count = count + 1" ng-init="count=0">
32860         Increment (on mouse down)
32861       </button>
32862       count: {{count}}
32863      </file>
32864    </example>
32865  */
32866
32867
32868 /**
32869  * @ngdoc directive
32870  * @name ngMouseup
32871  *
32872  * @description
32873  * Specify custom behavior on mouseup event.
32874  *
32875  * @element ANY
32876  * @priority 0
32877  * @param {expression} ngMouseup {@link guide/expression Expression} to evaluate upon
32878  * mouseup. ({@link guide/expression#-event- Event object is available as `$event`})
32879  *
32880  * @example
32881    <example>
32882      <file name="index.html">
32883       <button ng-mouseup="count = count + 1" ng-init="count=0">
32884         Increment (on mouse up)
32885       </button>
32886       count: {{count}}
32887      </file>
32888    </example>
32889  */
32890
32891 /**
32892  * @ngdoc directive
32893  * @name ngMouseover
32894  *
32895  * @description
32896  * Specify custom behavior on mouseover event.
32897  *
32898  * @element ANY
32899  * @priority 0
32900  * @param {expression} ngMouseover {@link guide/expression Expression} to evaluate upon
32901  * mouseover. ({@link guide/expression#-event- Event object is available as `$event`})
32902  *
32903  * @example
32904    <example>
32905      <file name="index.html">
32906       <button ng-mouseover="count = count + 1" ng-init="count=0">
32907         Increment (when mouse is over)
32908       </button>
32909       count: {{count}}
32910      </file>
32911    </example>
32912  */
32913
32914
32915 /**
32916  * @ngdoc directive
32917  * @name ngMouseenter
32918  *
32919  * @description
32920  * Specify custom behavior on mouseenter event.
32921  *
32922  * @element ANY
32923  * @priority 0
32924  * @param {expression} ngMouseenter {@link guide/expression Expression} to evaluate upon
32925  * mouseenter. ({@link guide/expression#-event- Event object is available as `$event`})
32926  *
32927  * @example
32928    <example>
32929      <file name="index.html">
32930       <button ng-mouseenter="count = count + 1" ng-init="count=0">
32931         Increment (when mouse enters)
32932       </button>
32933       count: {{count}}
32934      </file>
32935    </example>
32936  */
32937
32938
32939 /**
32940  * @ngdoc directive
32941  * @name ngMouseleave
32942  *
32943  * @description
32944  * Specify custom behavior on mouseleave event.
32945  *
32946  * @element ANY
32947  * @priority 0
32948  * @param {expression} ngMouseleave {@link guide/expression Expression} to evaluate upon
32949  * mouseleave. ({@link guide/expression#-event- Event object is available as `$event`})
32950  *
32951  * @example
32952    <example>
32953      <file name="index.html">
32954       <button ng-mouseleave="count = count + 1" ng-init="count=0">
32955         Increment (when mouse leaves)
32956       </button>
32957       count: {{count}}
32958      </file>
32959    </example>
32960  */
32961
32962
32963 /**
32964  * @ngdoc directive
32965  * @name ngMousemove
32966  *
32967  * @description
32968  * Specify custom behavior on mousemove event.
32969  *
32970  * @element ANY
32971  * @priority 0
32972  * @param {expression} ngMousemove {@link guide/expression Expression} to evaluate upon
32973  * mousemove. ({@link guide/expression#-event- Event object is available as `$event`})
32974  *
32975  * @example
32976    <example>
32977      <file name="index.html">
32978       <button ng-mousemove="count = count + 1" ng-init="count=0">
32979         Increment (when mouse moves)
32980       </button>
32981       count: {{count}}
32982      </file>
32983    </example>
32984  */
32985
32986
32987 /**
32988  * @ngdoc directive
32989  * @name ngKeydown
32990  *
32991  * @description
32992  * Specify custom behavior on keydown event.
32993  *
32994  * @element ANY
32995  * @priority 0
32996  * @param {expression} ngKeydown {@link guide/expression Expression} to evaluate upon
32997  * keydown. (Event object is available as `$event` and can be interrogated for keyCode, altKey, etc.)
32998  *
32999  * @example
33000    <example>
33001      <file name="index.html">
33002       <input ng-keydown="count = count + 1" ng-init="count=0">
33003       key down count: {{count}}
33004      </file>
33005    </example>
33006  */
33007
33008
33009 /**
33010  * @ngdoc directive
33011  * @name ngKeyup
33012  *
33013  * @description
33014  * Specify custom behavior on keyup event.
33015  *
33016  * @element ANY
33017  * @priority 0
33018  * @param {expression} ngKeyup {@link guide/expression Expression} to evaluate upon
33019  * keyup. (Event object is available as `$event` and can be interrogated for keyCode, altKey, etc.)
33020  *
33021  * @example
33022    <example>
33023      <file name="index.html">
33024        <p>Typing in the input box below updates the key count</p>
33025        <input ng-keyup="count = count + 1" ng-init="count=0"> key up count: {{count}}
33026
33027        <p>Typing in the input box below updates the keycode</p>
33028        <input ng-keyup="event=$event">
33029        <p>event keyCode: {{ event.keyCode }}</p>
33030        <p>event altKey: {{ event.altKey }}</p>
33031      </file>
33032    </example>
33033  */
33034
33035
33036 /**
33037  * @ngdoc directive
33038  * @name ngKeypress
33039  *
33040  * @description
33041  * Specify custom behavior on keypress event.
33042  *
33043  * @element ANY
33044  * @param {expression} ngKeypress {@link guide/expression Expression} to evaluate upon
33045  * keypress. ({@link guide/expression#-event- Event object is available as `$event`}
33046  * and can be interrogated for keyCode, altKey, etc.)
33047  *
33048  * @example
33049    <example>
33050      <file name="index.html">
33051       <input ng-keypress="count = count + 1" ng-init="count=0">
33052       key press count: {{count}}
33053      </file>
33054    </example>
33055  */
33056
33057
33058 /**
33059  * @ngdoc directive
33060  * @name ngSubmit
33061  *
33062  * @description
33063  * Enables binding angular expressions to onsubmit events.
33064  *
33065  * Additionally it prevents the default action (which for form means sending the request to the
33066  * server and reloading the current page), but only if the form does not contain `action`,
33067  * `data-action`, or `x-action` attributes.
33068  *
33069  * <div class="alert alert-warning">
33070  * **Warning:** Be careful not to cause "double-submission" by using both the `ngClick` and
33071  * `ngSubmit` handlers together. See the
33072  * {@link form#submitting-a-form-and-preventing-the-default-action `form` directive documentation}
33073  * for a detailed discussion of when `ngSubmit` may be triggered.
33074  * </div>
33075  *
33076  * @element form
33077  * @priority 0
33078  * @param {expression} ngSubmit {@link guide/expression Expression} to eval.
33079  * ({@link guide/expression#-event- Event object is available as `$event`})
33080  *
33081  * @example
33082    <example module="submitExample">
33083      <file name="index.html">
33084       <script>
33085         angular.module('submitExample', [])
33086           .controller('ExampleController', ['$scope', function($scope) {
33087             $scope.list = [];
33088             $scope.text = 'hello';
33089             $scope.submit = function() {
33090               if ($scope.text) {
33091                 $scope.list.push(this.text);
33092                 $scope.text = '';
33093               }
33094             };
33095           }]);
33096       </script>
33097       <form ng-submit="submit()" ng-controller="ExampleController">
33098         Enter text and hit enter:
33099         <input type="text" ng-model="text" name="text" />
33100         <input type="submit" id="submit" value="Submit" />
33101         <pre>list={{list}}</pre>
33102       </form>
33103      </file>
33104      <file name="protractor.js" type="protractor">
33105        it('should check ng-submit', function() {
33106          expect(element(by.binding('list')).getText()).toBe('list=[]');
33107          element(by.css('#submit')).click();
33108          expect(element(by.binding('list')).getText()).toContain('hello');
33109          expect(element(by.model('text')).getAttribute('value')).toBe('');
33110        });
33111        it('should ignore empty strings', function() {
33112          expect(element(by.binding('list')).getText()).toBe('list=[]');
33113          element(by.css('#submit')).click();
33114          element(by.css('#submit')).click();
33115          expect(element(by.binding('list')).getText()).toContain('hello');
33116         });
33117      </file>
33118    </example>
33119  */
33120
33121 /**
33122  * @ngdoc directive
33123  * @name ngFocus
33124  *
33125  * @description
33126  * Specify custom behavior on focus event.
33127  *
33128  * Note: As the `focus` event is executed synchronously when calling `input.focus()`
33129  * AngularJS executes the expression using `scope.$evalAsync` if the event is fired
33130  * during an `$apply` to ensure a consistent state.
33131  *
33132  * @element window, input, select, textarea, a
33133  * @priority 0
33134  * @param {expression} ngFocus {@link guide/expression Expression} to evaluate upon
33135  * focus. ({@link guide/expression#-event- Event object is available as `$event`})
33136  *
33137  * @example
33138  * See {@link ng.directive:ngClick ngClick}
33139  */
33140
33141 /**
33142  * @ngdoc directive
33143  * @name ngBlur
33144  *
33145  * @description
33146  * Specify custom behavior on blur event.
33147  *
33148  * A [blur event](https://developer.mozilla.org/en-US/docs/Web/Events/blur) fires when
33149  * an element has lost focus.
33150  *
33151  * Note: As the `blur` event is executed synchronously also during DOM manipulations
33152  * (e.g. removing a focussed input),
33153  * AngularJS executes the expression using `scope.$evalAsync` if the event is fired
33154  * during an `$apply` to ensure a consistent state.
33155  *
33156  * @element window, input, select, textarea, a
33157  * @priority 0
33158  * @param {expression} ngBlur {@link guide/expression Expression} to evaluate upon
33159  * blur. ({@link guide/expression#-event- Event object is available as `$event`})
33160  *
33161  * @example
33162  * See {@link ng.directive:ngClick ngClick}
33163  */
33164
33165 /**
33166  * @ngdoc directive
33167  * @name ngCopy
33168  *
33169  * @description
33170  * Specify custom behavior on copy event.
33171  *
33172  * @element window, input, select, textarea, a
33173  * @priority 0
33174  * @param {expression} ngCopy {@link guide/expression Expression} to evaluate upon
33175  * copy. ({@link guide/expression#-event- Event object is available as `$event`})
33176  *
33177  * @example
33178    <example>
33179      <file name="index.html">
33180       <input ng-copy="copied=true" ng-init="copied=false; value='copy me'" ng-model="value">
33181       copied: {{copied}}
33182      </file>
33183    </example>
33184  */
33185
33186 /**
33187  * @ngdoc directive
33188  * @name ngCut
33189  *
33190  * @description
33191  * Specify custom behavior on cut event.
33192  *
33193  * @element window, input, select, textarea, a
33194  * @priority 0
33195  * @param {expression} ngCut {@link guide/expression Expression} to evaluate upon
33196  * cut. ({@link guide/expression#-event- Event object is available as `$event`})
33197  *
33198  * @example
33199    <example>
33200      <file name="index.html">
33201       <input ng-cut="cut=true" ng-init="cut=false; value='cut me'" ng-model="value">
33202       cut: {{cut}}
33203      </file>
33204    </example>
33205  */
33206
33207 /**
33208  * @ngdoc directive
33209  * @name ngPaste
33210  *
33211  * @description
33212  * Specify custom behavior on paste event.
33213  *
33214  * @element window, input, select, textarea, a
33215  * @priority 0
33216  * @param {expression} ngPaste {@link guide/expression Expression} to evaluate upon
33217  * paste. ({@link guide/expression#-event- Event object is available as `$event`})
33218  *
33219  * @example
33220    <example>
33221      <file name="index.html">
33222       <input ng-paste="paste=true" ng-init="paste=false" placeholder='paste here'>
33223       pasted: {{paste}}
33224      </file>
33225    </example>
33226  */
33227
33228 /**
33229  * @ngdoc directive
33230  * @name ngIf
33231  * @restrict A
33232  * @multiElement
33233  *
33234  * @description
33235  * The `ngIf` directive removes or recreates a portion of the DOM tree based on an
33236  * {expression}. If the expression assigned to `ngIf` evaluates to a false
33237  * value then the element is removed from the DOM, otherwise a clone of the
33238  * element is reinserted into the DOM.
33239  *
33240  * `ngIf` differs from `ngShow` and `ngHide` in that `ngIf` completely removes and recreates the
33241  * element in the DOM rather than changing its visibility via the `display` css property.  A common
33242  * case when this difference is significant is when using css selectors that rely on an element's
33243  * position within the DOM, such as the `:first-child` or `:last-child` pseudo-classes.
33244  *
33245  * Note that when an element is removed using `ngIf` its scope is destroyed and a new scope
33246  * is created when the element is restored.  The scope created within `ngIf` inherits from
33247  * its parent scope using
33248  * [prototypal inheritance](https://github.com/angular/angular.js/wiki/Understanding-Scopes#javascript-prototypal-inheritance).
33249  * An important implication of this is if `ngModel` is used within `ngIf` to bind to
33250  * a javascript primitive defined in the parent scope. In this case any modifications made to the
33251  * variable within the child scope will override (hide) the value in the parent scope.
33252  *
33253  * Also, `ngIf` recreates elements using their compiled state. An example of this behavior
33254  * is if an element's class attribute is directly modified after it's compiled, using something like
33255  * jQuery's `.addClass()` method, and the element is later removed. When `ngIf` recreates the element
33256  * the added class will be lost because the original compiled state is used to regenerate the element.
33257  *
33258  * Additionally, you can provide animations via the `ngAnimate` module to animate the `enter`
33259  * and `leave` effects.
33260  *
33261  * @animations
33262  * enter - happens just after the `ngIf` contents change and a new DOM element is created and injected into the `ngIf` container
33263  * leave - happens just before the `ngIf` contents are removed from the DOM
33264  *
33265  * @element ANY
33266  * @scope
33267  * @priority 600
33268  * @param {expression} ngIf If the {@link guide/expression expression} is falsy then
33269  *     the element is removed from the DOM tree. If it is truthy a copy of the compiled
33270  *     element is added to the DOM tree.
33271  *
33272  * @example
33273   <example module="ngAnimate" deps="angular-animate.js" animations="true">
33274     <file name="index.html">
33275       <label>Click me: <input type="checkbox" ng-model="checked" ng-init="checked=true" /></label><br/>
33276       Show when checked:
33277       <span ng-if="checked" class="animate-if">
33278         This is removed when the checkbox is unchecked.
33279       </span>
33280     </file>
33281     <file name="animations.css">
33282       .animate-if {
33283         background:white;
33284         border:1px solid black;
33285         padding:10px;
33286       }
33287
33288       .animate-if.ng-enter, .animate-if.ng-leave {
33289         transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
33290       }
33291
33292       .animate-if.ng-enter,
33293       .animate-if.ng-leave.ng-leave-active {
33294         opacity:0;
33295       }
33296
33297       .animate-if.ng-leave,
33298       .animate-if.ng-enter.ng-enter-active {
33299         opacity:1;
33300       }
33301     </file>
33302   </example>
33303  */
33304 var ngIfDirective = ['$animate', function($animate) {
33305   return {
33306     multiElement: true,
33307     transclude: 'element',
33308     priority: 600,
33309     terminal: true,
33310     restrict: 'A',
33311     $$tlb: true,
33312     link: function($scope, $element, $attr, ctrl, $transclude) {
33313         var block, childScope, previousElements;
33314         $scope.$watch($attr.ngIf, function ngIfWatchAction(value) {
33315
33316           if (value) {
33317             if (!childScope) {
33318               $transclude(function(clone, newScope) {
33319                 childScope = newScope;
33320                 clone[clone.length++] = document.createComment(' end ngIf: ' + $attr.ngIf + ' ');
33321                 // Note: We only need the first/last node of the cloned nodes.
33322                 // However, we need to keep the reference to the jqlite wrapper as it might be changed later
33323                 // by a directive with templateUrl when its template arrives.
33324                 block = {
33325                   clone: clone
33326                 };
33327                 $animate.enter(clone, $element.parent(), $element);
33328               });
33329             }
33330           } else {
33331             if (previousElements) {
33332               previousElements.remove();
33333               previousElements = null;
33334             }
33335             if (childScope) {
33336               childScope.$destroy();
33337               childScope = null;
33338             }
33339             if (block) {
33340               previousElements = getBlockNodes(block.clone);
33341               $animate.leave(previousElements).then(function() {
33342                 previousElements = null;
33343               });
33344               block = null;
33345             }
33346           }
33347         });
33348     }
33349   };
33350 }];
33351
33352 /**
33353  * @ngdoc directive
33354  * @name ngInclude
33355  * @restrict ECA
33356  *
33357  * @description
33358  * Fetches, compiles and includes an external HTML fragment.
33359  *
33360  * By default, the template URL is restricted to the same domain and protocol as the
33361  * application document. This is done by calling {@link $sce#getTrustedResourceUrl
33362  * $sce.getTrustedResourceUrl} on it. To load templates from other domains or protocols
33363  * you may either {@link ng.$sceDelegateProvider#resourceUrlWhitelist whitelist them} or
33364  * {@link $sce#trustAsResourceUrl wrap them} as trusted values. Refer to Angular's {@link
33365  * ng.$sce Strict Contextual Escaping}.
33366  *
33367  * In addition, the browser's
33368  * [Same Origin Policy](https://code.google.com/p/browsersec/wiki/Part2#Same-origin_policy_for_XMLHttpRequest)
33369  * and [Cross-Origin Resource Sharing (CORS)](http://www.w3.org/TR/cors/)
33370  * policy may further restrict whether the template is successfully loaded.
33371  * For example, `ngInclude` won't work for cross-domain requests on all browsers and for `file://`
33372  * access on some browsers.
33373  *
33374  * @animations
33375  * enter - animation is used to bring new content into the browser.
33376  * leave - animation is used to animate existing content away.
33377  *
33378  * The enter and leave animation occur concurrently.
33379  *
33380  * @scope
33381  * @priority 400
33382  *
33383  * @param {string} ngInclude|src angular expression evaluating to URL. If the source is a string constant,
33384  *                 make sure you wrap it in **single** quotes, e.g. `src="'myPartialTemplate.html'"`.
33385  * @param {string=} onload Expression to evaluate when a new partial is loaded.
33386  *                  <div class="alert alert-warning">
33387  *                  **Note:** When using onload on SVG elements in IE11, the browser will try to call
33388  *                  a function with the name on the window element, which will usually throw a
33389  *                  "function is undefined" error. To fix this, you can instead use `data-onload` or a
33390  *                  different form that {@link guide/directive#normalization matches} `onload`.
33391  *                  </div>
33392    *
33393  * @param {string=} autoscroll Whether `ngInclude` should call {@link ng.$anchorScroll
33394  *                  $anchorScroll} to scroll the viewport after the content is loaded.
33395  *
33396  *                  - If the attribute is not set, disable scrolling.
33397  *                  - If the attribute is set without value, enable scrolling.
33398  *                  - Otherwise enable scrolling only if the expression evaluates to truthy value.
33399  *
33400  * @example
33401   <example module="includeExample" deps="angular-animate.js" animations="true">
33402     <file name="index.html">
33403      <div ng-controller="ExampleController">
33404        <select ng-model="template" ng-options="t.name for t in templates">
33405         <option value="">(blank)</option>
33406        </select>
33407        url of the template: <code>{{template.url}}</code>
33408        <hr/>
33409        <div class="slide-animate-container">
33410          <div class="slide-animate" ng-include="template.url"></div>
33411        </div>
33412      </div>
33413     </file>
33414     <file name="script.js">
33415       angular.module('includeExample', ['ngAnimate'])
33416         .controller('ExampleController', ['$scope', function($scope) {
33417           $scope.templates =
33418             [ { name: 'template1.html', url: 'template1.html'},
33419               { name: 'template2.html', url: 'template2.html'} ];
33420           $scope.template = $scope.templates[0];
33421         }]);
33422      </file>
33423     <file name="template1.html">
33424       Content of template1.html
33425     </file>
33426     <file name="template2.html">
33427       Content of template2.html
33428     </file>
33429     <file name="animations.css">
33430       .slide-animate-container {
33431         position:relative;
33432         background:white;
33433         border:1px solid black;
33434         height:40px;
33435         overflow:hidden;
33436       }
33437
33438       .slide-animate {
33439         padding:10px;
33440       }
33441
33442       .slide-animate.ng-enter, .slide-animate.ng-leave {
33443         transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
33444
33445         position:absolute;
33446         top:0;
33447         left:0;
33448         right:0;
33449         bottom:0;
33450         display:block;
33451         padding:10px;
33452       }
33453
33454       .slide-animate.ng-enter {
33455         top:-50px;
33456       }
33457       .slide-animate.ng-enter.ng-enter-active {
33458         top:0;
33459       }
33460
33461       .slide-animate.ng-leave {
33462         top:0;
33463       }
33464       .slide-animate.ng-leave.ng-leave-active {
33465         top:50px;
33466       }
33467     </file>
33468     <file name="protractor.js" type="protractor">
33469       var templateSelect = element(by.model('template'));
33470       var includeElem = element(by.css('[ng-include]'));
33471
33472       it('should load template1.html', function() {
33473         expect(includeElem.getText()).toMatch(/Content of template1.html/);
33474       });
33475
33476       it('should load template2.html', function() {
33477         if (browser.params.browser == 'firefox') {
33478           // Firefox can't handle using selects
33479           // See https://github.com/angular/protractor/issues/480
33480           return;
33481         }
33482         templateSelect.click();
33483         templateSelect.all(by.css('option')).get(2).click();
33484         expect(includeElem.getText()).toMatch(/Content of template2.html/);
33485       });
33486
33487       it('should change to blank', function() {
33488         if (browser.params.browser == 'firefox') {
33489           // Firefox can't handle using selects
33490           return;
33491         }
33492         templateSelect.click();
33493         templateSelect.all(by.css('option')).get(0).click();
33494         expect(includeElem.isPresent()).toBe(false);
33495       });
33496     </file>
33497   </example>
33498  */
33499
33500
33501 /**
33502  * @ngdoc event
33503  * @name ngInclude#$includeContentRequested
33504  * @eventType emit on the scope ngInclude was declared in
33505  * @description
33506  * Emitted every time the ngInclude content is requested.
33507  *
33508  * @param {Object} angularEvent Synthetic event object.
33509  * @param {String} src URL of content to load.
33510  */
33511
33512
33513 /**
33514  * @ngdoc event
33515  * @name ngInclude#$includeContentLoaded
33516  * @eventType emit on the current ngInclude scope
33517  * @description
33518  * Emitted every time the ngInclude content is reloaded.
33519  *
33520  * @param {Object} angularEvent Synthetic event object.
33521  * @param {String} src URL of content to load.
33522  */
33523
33524
33525 /**
33526  * @ngdoc event
33527  * @name ngInclude#$includeContentError
33528  * @eventType emit on the scope ngInclude was declared in
33529  * @description
33530  * Emitted when a template HTTP request yields an erroneous response (status < 200 || status > 299)
33531  *
33532  * @param {Object} angularEvent Synthetic event object.
33533  * @param {String} src URL of content to load.
33534  */
33535 var ngIncludeDirective = ['$templateRequest', '$anchorScroll', '$animate',
33536                   function($templateRequest,   $anchorScroll,   $animate) {
33537   return {
33538     restrict: 'ECA',
33539     priority: 400,
33540     terminal: true,
33541     transclude: 'element',
33542     controller: angular.noop,
33543     compile: function(element, attr) {
33544       var srcExp = attr.ngInclude || attr.src,
33545           onloadExp = attr.onload || '',
33546           autoScrollExp = attr.autoscroll;
33547
33548       return function(scope, $element, $attr, ctrl, $transclude) {
33549         var changeCounter = 0,
33550             currentScope,
33551             previousElement,
33552             currentElement;
33553
33554         var cleanupLastIncludeContent = function() {
33555           if (previousElement) {
33556             previousElement.remove();
33557             previousElement = null;
33558           }
33559           if (currentScope) {
33560             currentScope.$destroy();
33561             currentScope = null;
33562           }
33563           if (currentElement) {
33564             $animate.leave(currentElement).then(function() {
33565               previousElement = null;
33566             });
33567             previousElement = currentElement;
33568             currentElement = null;
33569           }
33570         };
33571
33572         scope.$watch(srcExp, function ngIncludeWatchAction(src) {
33573           var afterAnimation = function() {
33574             if (isDefined(autoScrollExp) && (!autoScrollExp || scope.$eval(autoScrollExp))) {
33575               $anchorScroll();
33576             }
33577           };
33578           var thisChangeId = ++changeCounter;
33579
33580           if (src) {
33581             //set the 2nd param to true to ignore the template request error so that the inner
33582             //contents and scope can be cleaned up.
33583             $templateRequest(src, true).then(function(response) {
33584               if (thisChangeId !== changeCounter) return;
33585               var newScope = scope.$new();
33586               ctrl.template = response;
33587
33588               // Note: This will also link all children of ng-include that were contained in the original
33589               // html. If that content contains controllers, ... they could pollute/change the scope.
33590               // However, using ng-include on an element with additional content does not make sense...
33591               // Note: We can't remove them in the cloneAttchFn of $transclude as that
33592               // function is called before linking the content, which would apply child
33593               // directives to non existing elements.
33594               var clone = $transclude(newScope, function(clone) {
33595                 cleanupLastIncludeContent();
33596                 $animate.enter(clone, null, $element).then(afterAnimation);
33597               });
33598
33599               currentScope = newScope;
33600               currentElement = clone;
33601
33602               currentScope.$emit('$includeContentLoaded', src);
33603               scope.$eval(onloadExp);
33604             }, function() {
33605               if (thisChangeId === changeCounter) {
33606                 cleanupLastIncludeContent();
33607                 scope.$emit('$includeContentError', src);
33608               }
33609             });
33610             scope.$emit('$includeContentRequested', src);
33611           } else {
33612             cleanupLastIncludeContent();
33613             ctrl.template = null;
33614           }
33615         });
33616       };
33617     }
33618   };
33619 }];
33620
33621 // This directive is called during the $transclude call of the first `ngInclude` directive.
33622 // It will replace and compile the content of the element with the loaded template.
33623 // We need this directive so that the element content is already filled when
33624 // the link function of another directive on the same element as ngInclude
33625 // is called.
33626 var ngIncludeFillContentDirective = ['$compile',
33627   function($compile) {
33628     return {
33629       restrict: 'ECA',
33630       priority: -400,
33631       require: 'ngInclude',
33632       link: function(scope, $element, $attr, ctrl) {
33633         if (/SVG/.test($element[0].toString())) {
33634           // WebKit: https://bugs.webkit.org/show_bug.cgi?id=135698 --- SVG elements do not
33635           // support innerHTML, so detect this here and try to generate the contents
33636           // specially.
33637           $element.empty();
33638           $compile(jqLiteBuildFragment(ctrl.template, document).childNodes)(scope,
33639               function namespaceAdaptedClone(clone) {
33640             $element.append(clone);
33641           }, {futureParentElement: $element});
33642           return;
33643         }
33644
33645         $element.html(ctrl.template);
33646         $compile($element.contents())(scope);
33647       }
33648     };
33649   }];
33650
33651 /**
33652  * @ngdoc directive
33653  * @name ngInit
33654  * @restrict AC
33655  *
33656  * @description
33657  * The `ngInit` directive allows you to evaluate an expression in the
33658  * current scope.
33659  *
33660  * <div class="alert alert-danger">
33661  * This directive can be abused to add unnecessary amounts of logic into your templates.
33662  * There are only a few appropriate uses of `ngInit`, such as for aliasing special properties of
33663  * {@link ng.directive:ngRepeat `ngRepeat`}, as seen in the demo below; and for injecting data via
33664  * server side scripting. Besides these few cases, you should use {@link guide/controller controllers}
33665  * rather than `ngInit` to initialize values on a scope.
33666  * </div>
33667  *
33668  * <div class="alert alert-warning">
33669  * **Note**: If you have assignment in `ngInit` along with a {@link ng.$filter `filter`}, make
33670  * sure you have parentheses to ensure correct operator precedence:
33671  * <pre class="prettyprint">
33672  * `<div ng-init="test1 = ($index | toString)"></div>`
33673  * </pre>
33674  * </div>
33675  *
33676  * @priority 450
33677  *
33678  * @element ANY
33679  * @param {expression} ngInit {@link guide/expression Expression} to eval.
33680  *
33681  * @example
33682    <example module="initExample">
33683      <file name="index.html">
33684    <script>
33685      angular.module('initExample', [])
33686        .controller('ExampleController', ['$scope', function($scope) {
33687          $scope.list = [['a', 'b'], ['c', 'd']];
33688        }]);
33689    </script>
33690    <div ng-controller="ExampleController">
33691      <div ng-repeat="innerList in list" ng-init="outerIndex = $index">
33692        <div ng-repeat="value in innerList" ng-init="innerIndex = $index">
33693           <span class="example-init">list[ {{outerIndex}} ][ {{innerIndex}} ] = {{value}};</span>
33694        </div>
33695      </div>
33696    </div>
33697      </file>
33698      <file name="protractor.js" type="protractor">
33699        it('should alias index positions', function() {
33700          var elements = element.all(by.css('.example-init'));
33701          expect(elements.get(0).getText()).toBe('list[ 0 ][ 0 ] = a;');
33702          expect(elements.get(1).getText()).toBe('list[ 0 ][ 1 ] = b;');
33703          expect(elements.get(2).getText()).toBe('list[ 1 ][ 0 ] = c;');
33704          expect(elements.get(3).getText()).toBe('list[ 1 ][ 1 ] = d;');
33705        });
33706      </file>
33707    </example>
33708  */
33709 var ngInitDirective = ngDirective({
33710   priority: 450,
33711   compile: function() {
33712     return {
33713       pre: function(scope, element, attrs) {
33714         scope.$eval(attrs.ngInit);
33715       }
33716     };
33717   }
33718 });
33719
33720 /**
33721  * @ngdoc directive
33722  * @name ngList
33723  *
33724  * @description
33725  * Text input that converts between a delimited string and an array of strings. The default
33726  * delimiter is a comma followed by a space - equivalent to `ng-list=", "`. You can specify a custom
33727  * delimiter as the value of the `ngList` attribute - for example, `ng-list=" | "`.
33728  *
33729  * The behaviour of the directive is affected by the use of the `ngTrim` attribute.
33730  * * If `ngTrim` is set to `"false"` then whitespace around both the separator and each
33731  *   list item is respected. This implies that the user of the directive is responsible for
33732  *   dealing with whitespace but also allows you to use whitespace as a delimiter, such as a
33733  *   tab or newline character.
33734  * * Otherwise whitespace around the delimiter is ignored when splitting (although it is respected
33735  *   when joining the list items back together) and whitespace around each list item is stripped
33736  *   before it is added to the model.
33737  *
33738  * ### Example with Validation
33739  *
33740  * <example name="ngList-directive" module="listExample">
33741  *   <file name="app.js">
33742  *      angular.module('listExample', [])
33743  *        .controller('ExampleController', ['$scope', function($scope) {
33744  *          $scope.names = ['morpheus', 'neo', 'trinity'];
33745  *        }]);
33746  *   </file>
33747  *   <file name="index.html">
33748  *    <form name="myForm" ng-controller="ExampleController">
33749  *      <label>List: <input name="namesInput" ng-model="names" ng-list required></label>
33750  *      <span role="alert">
33751  *        <span class="error" ng-show="myForm.namesInput.$error.required">
33752  *        Required!</span>
33753  *      </span>
33754  *      <br>
33755  *      <tt>names = {{names}}</tt><br/>
33756  *      <tt>myForm.namesInput.$valid = {{myForm.namesInput.$valid}}</tt><br/>
33757  *      <tt>myForm.namesInput.$error = {{myForm.namesInput.$error}}</tt><br/>
33758  *      <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
33759  *      <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
33760  *     </form>
33761  *   </file>
33762  *   <file name="protractor.js" type="protractor">
33763  *     var listInput = element(by.model('names'));
33764  *     var names = element(by.exactBinding('names'));
33765  *     var valid = element(by.binding('myForm.namesInput.$valid'));
33766  *     var error = element(by.css('span.error'));
33767  *
33768  *     it('should initialize to model', function() {
33769  *       expect(names.getText()).toContain('["morpheus","neo","trinity"]');
33770  *       expect(valid.getText()).toContain('true');
33771  *       expect(error.getCssValue('display')).toBe('none');
33772  *     });
33773  *
33774  *     it('should be invalid if empty', function() {
33775  *       listInput.clear();
33776  *       listInput.sendKeys('');
33777  *
33778  *       expect(names.getText()).toContain('');
33779  *       expect(valid.getText()).toContain('false');
33780  *       expect(error.getCssValue('display')).not.toBe('none');
33781  *     });
33782  *   </file>
33783  * </example>
33784  *
33785  * ### Example - splitting on newline
33786  * <example name="ngList-directive-newlines">
33787  *   <file name="index.html">
33788  *    <textarea ng-model="list" ng-list="&#10;" ng-trim="false"></textarea>
33789  *    <pre>{{ list | json }}</pre>
33790  *   </file>
33791  *   <file name="protractor.js" type="protractor">
33792  *     it("should split the text by newlines", function() {
33793  *       var listInput = element(by.model('list'));
33794  *       var output = element(by.binding('list | json'));
33795  *       listInput.sendKeys('abc\ndef\nghi');
33796  *       expect(output.getText()).toContain('[\n  "abc",\n  "def",\n  "ghi"\n]');
33797  *     });
33798  *   </file>
33799  * </example>
33800  *
33801  * @element input
33802  * @param {string=} ngList optional delimiter that should be used to split the value.
33803  */
33804 var ngListDirective = function() {
33805   return {
33806     restrict: 'A',
33807     priority: 100,
33808     require: 'ngModel',
33809     link: function(scope, element, attr, ctrl) {
33810       // We want to control whitespace trimming so we use this convoluted approach
33811       // to access the ngList attribute, which doesn't pre-trim the attribute
33812       var ngList = element.attr(attr.$attr.ngList) || ', ';
33813       var trimValues = attr.ngTrim !== 'false';
33814       var separator = trimValues ? trim(ngList) : ngList;
33815
33816       var parse = function(viewValue) {
33817         // If the viewValue is invalid (say required but empty) it will be `undefined`
33818         if (isUndefined(viewValue)) return;
33819
33820         var list = [];
33821
33822         if (viewValue) {
33823           forEach(viewValue.split(separator), function(value) {
33824             if (value) list.push(trimValues ? trim(value) : value);
33825           });
33826         }
33827
33828         return list;
33829       };
33830
33831       ctrl.$parsers.push(parse);
33832       ctrl.$formatters.push(function(value) {
33833         if (isArray(value)) {
33834           return value.join(ngList);
33835         }
33836
33837         return undefined;
33838       });
33839
33840       // Override the standard $isEmpty because an empty array means the input is empty.
33841       ctrl.$isEmpty = function(value) {
33842         return !value || !value.length;
33843       };
33844     }
33845   };
33846 };
33847
33848 /* global VALID_CLASS: true,
33849   INVALID_CLASS: true,
33850   PRISTINE_CLASS: true,
33851   DIRTY_CLASS: true,
33852   UNTOUCHED_CLASS: true,
33853   TOUCHED_CLASS: true,
33854 */
33855
33856 var VALID_CLASS = 'ng-valid',
33857     INVALID_CLASS = 'ng-invalid',
33858     PRISTINE_CLASS = 'ng-pristine',
33859     DIRTY_CLASS = 'ng-dirty',
33860     UNTOUCHED_CLASS = 'ng-untouched',
33861     TOUCHED_CLASS = 'ng-touched',
33862     PENDING_CLASS = 'ng-pending';
33863
33864 var ngModelMinErr = minErr('ngModel');
33865
33866 /**
33867  * @ngdoc type
33868  * @name ngModel.NgModelController
33869  *
33870  * @property {*} $viewValue The actual value from the control's view. For `input` elements, this is a
33871  * String. See {@link ngModel.NgModelController#$setViewValue} for information about when the $viewValue
33872  * is set.
33873  * @property {*} $modelValue The value in the model that the control is bound to.
33874  * @property {Array.<Function>} $parsers Array of functions to execute, as a pipeline, whenever
33875        the control reads value from the DOM. The functions are called in array order, each passing
33876        its return value through to the next. The last return value is forwarded to the
33877        {@link ngModel.NgModelController#$validators `$validators`} collection.
33878
33879 Parsers are used to sanitize / convert the {@link ngModel.NgModelController#$viewValue
33880 `$viewValue`}.
33881
33882 Returning `undefined` from a parser means a parse error occurred. In that case,
33883 no {@link ngModel.NgModelController#$validators `$validators`} will run and the `ngModel`
33884 will be set to `undefined` unless {@link ngModelOptions `ngModelOptions.allowInvalid`}
33885 is set to `true`. The parse error is stored in `ngModel.$error.parse`.
33886
33887  *
33888  * @property {Array.<Function>} $formatters Array of functions to execute, as a pipeline, whenever
33889        the model value changes. The functions are called in reverse array order, each passing the value through to the
33890        next. The last return value is used as the actual DOM value.
33891        Used to format / convert values for display in the control.
33892  * ```js
33893  * function formatter(value) {
33894  *   if (value) {
33895  *     return value.toUpperCase();
33896  *   }
33897  * }
33898  * ngModel.$formatters.push(formatter);
33899  * ```
33900  *
33901  * @property {Object.<string, function>} $validators A collection of validators that are applied
33902  *      whenever the model value changes. The key value within the object refers to the name of the
33903  *      validator while the function refers to the validation operation. The validation operation is
33904  *      provided with the model value as an argument and must return a true or false value depending
33905  *      on the response of that validation.
33906  *
33907  * ```js
33908  * ngModel.$validators.validCharacters = function(modelValue, viewValue) {
33909  *   var value = modelValue || viewValue;
33910  *   return /[0-9]+/.test(value) &&
33911  *          /[a-z]+/.test(value) &&
33912  *          /[A-Z]+/.test(value) &&
33913  *          /\W+/.test(value);
33914  * };
33915  * ```
33916  *
33917  * @property {Object.<string, function>} $asyncValidators A collection of validations that are expected to
33918  *      perform an asynchronous validation (e.g. a HTTP request). The validation function that is provided
33919  *      is expected to return a promise when it is run during the model validation process. Once the promise
33920  *      is delivered then the validation status will be set to true when fulfilled and false when rejected.
33921  *      When the asynchronous validators are triggered, each of the validators will run in parallel and the model
33922  *      value will only be updated once all validators have been fulfilled. As long as an asynchronous validator
33923  *      is unfulfilled, its key will be added to the controllers `$pending` property. Also, all asynchronous validators
33924  *      will only run once all synchronous validators have passed.
33925  *
33926  * Please note that if $http is used then it is important that the server returns a success HTTP response code
33927  * in order to fulfill the validation and a status level of `4xx` in order to reject the validation.
33928  *
33929  * ```js
33930  * ngModel.$asyncValidators.uniqueUsername = function(modelValue, viewValue) {
33931  *   var value = modelValue || viewValue;
33932  *
33933  *   // Lookup user by username
33934  *   return $http.get('/api/users/' + value).
33935  *      then(function resolved() {
33936  *        //username exists, this means validation fails
33937  *        return $q.reject('exists');
33938  *      }, function rejected() {
33939  *        //username does not exist, therefore this validation passes
33940  *        return true;
33941  *      });
33942  * };
33943  * ```
33944  *
33945  * @property {Array.<Function>} $viewChangeListeners Array of functions to execute whenever the
33946  *     view value has changed. It is called with no arguments, and its return value is ignored.
33947  *     This can be used in place of additional $watches against the model value.
33948  *
33949  * @property {Object} $error An object hash with all failing validator ids as keys.
33950  * @property {Object} $pending An object hash with all pending validator ids as keys.
33951  *
33952  * @property {boolean} $untouched True if control has not lost focus yet.
33953  * @property {boolean} $touched True if control has lost focus.
33954  * @property {boolean} $pristine True if user has not interacted with the control yet.
33955  * @property {boolean} $dirty True if user has already interacted with the control.
33956  * @property {boolean} $valid True if there is no error.
33957  * @property {boolean} $invalid True if at least one error on the control.
33958  * @property {string} $name The name attribute of the control.
33959  *
33960  * @description
33961  *
33962  * `NgModelController` provides API for the {@link ngModel `ngModel`} directive.
33963  * The controller contains services for data-binding, validation, CSS updates, and value formatting
33964  * and parsing. It purposefully does not contain any logic which deals with DOM rendering or
33965  * listening to DOM events.
33966  * Such DOM related logic should be provided by other directives which make use of
33967  * `NgModelController` for data-binding to control elements.
33968  * Angular provides this DOM logic for most {@link input `input`} elements.
33969  * At the end of this page you can find a {@link ngModel.NgModelController#custom-control-example
33970  * custom control example} that uses `ngModelController` to bind to `contenteditable` elements.
33971  *
33972  * @example
33973  * ### Custom Control Example
33974  * This example shows how to use `NgModelController` with a custom control to achieve
33975  * data-binding. Notice how different directives (`contenteditable`, `ng-model`, and `required`)
33976  * collaborate together to achieve the desired result.
33977  *
33978  * `contenteditable` is an HTML5 attribute, which tells the browser to let the element
33979  * contents be edited in place by the user.
33980  *
33981  * We are using the {@link ng.service:$sce $sce} service here and include the {@link ngSanitize $sanitize}
33982  * module to automatically remove "bad" content like inline event listener (e.g. `<span onclick="...">`).
33983  * However, as we are using `$sce` the model can still decide to provide unsafe content if it marks
33984  * that content using the `$sce` service.
33985  *
33986  * <example name="NgModelController" module="customControl" deps="angular-sanitize.js">
33987     <file name="style.css">
33988       [contenteditable] {
33989         border: 1px solid black;
33990         background-color: white;
33991         min-height: 20px;
33992       }
33993
33994       .ng-invalid {
33995         border: 1px solid red;
33996       }
33997
33998     </file>
33999     <file name="script.js">
34000       angular.module('customControl', ['ngSanitize']).
34001         directive('contenteditable', ['$sce', function($sce) {
34002           return {
34003             restrict: 'A', // only activate on element attribute
34004             require: '?ngModel', // get a hold of NgModelController
34005             link: function(scope, element, attrs, ngModel) {
34006               if (!ngModel) return; // do nothing if no ng-model
34007
34008               // Specify how UI should be updated
34009               ngModel.$render = function() {
34010                 element.html($sce.getTrustedHtml(ngModel.$viewValue || ''));
34011               };
34012
34013               // Listen for change events to enable binding
34014               element.on('blur keyup change', function() {
34015                 scope.$evalAsync(read);
34016               });
34017               read(); // initialize
34018
34019               // Write data to the model
34020               function read() {
34021                 var html = element.html();
34022                 // When we clear the content editable the browser leaves a <br> behind
34023                 // If strip-br attribute is provided then we strip this out
34024                 if ( attrs.stripBr && html == '<br>' ) {
34025                   html = '';
34026                 }
34027                 ngModel.$setViewValue(html);
34028               }
34029             }
34030           };
34031         }]);
34032     </file>
34033     <file name="index.html">
34034       <form name="myForm">
34035        <div contenteditable
34036             name="myWidget" ng-model="userContent"
34037             strip-br="true"
34038             required>Change me!</div>
34039         <span ng-show="myForm.myWidget.$error.required">Required!</span>
34040        <hr>
34041        <textarea ng-model="userContent" aria-label="Dynamic textarea"></textarea>
34042       </form>
34043     </file>
34044     <file name="protractor.js" type="protractor">
34045     it('should data-bind and become invalid', function() {
34046       if (browser.params.browser == 'safari' || browser.params.browser == 'firefox') {
34047         // SafariDriver can't handle contenteditable
34048         // and Firefox driver can't clear contenteditables very well
34049         return;
34050       }
34051       var contentEditable = element(by.css('[contenteditable]'));
34052       var content = 'Change me!';
34053
34054       expect(contentEditable.getText()).toEqual(content);
34055
34056       contentEditable.clear();
34057       contentEditable.sendKeys(protractor.Key.BACK_SPACE);
34058       expect(contentEditable.getText()).toEqual('');
34059       expect(contentEditable.getAttribute('class')).toMatch(/ng-invalid-required/);
34060     });
34061     </file>
34062  * </example>
34063  *
34064  *
34065  */
34066 var NgModelController = ['$scope', '$exceptionHandler', '$attrs', '$element', '$parse', '$animate', '$timeout', '$rootScope', '$q', '$interpolate',
34067     function($scope, $exceptionHandler, $attr, $element, $parse, $animate, $timeout, $rootScope, $q, $interpolate) {
34068   this.$viewValue = Number.NaN;
34069   this.$modelValue = Number.NaN;
34070   this.$$rawModelValue = undefined; // stores the parsed modelValue / model set from scope regardless of validity.
34071   this.$validators = {};
34072   this.$asyncValidators = {};
34073   this.$parsers = [];
34074   this.$formatters = [];
34075   this.$viewChangeListeners = [];
34076   this.$untouched = true;
34077   this.$touched = false;
34078   this.$pristine = true;
34079   this.$dirty = false;
34080   this.$valid = true;
34081   this.$invalid = false;
34082   this.$error = {}; // keep invalid keys here
34083   this.$$success = {}; // keep valid keys here
34084   this.$pending = undefined; // keep pending keys here
34085   this.$name = $interpolate($attr.name || '', false)($scope);
34086   this.$$parentForm = nullFormCtrl;
34087
34088   var parsedNgModel = $parse($attr.ngModel),
34089       parsedNgModelAssign = parsedNgModel.assign,
34090       ngModelGet = parsedNgModel,
34091       ngModelSet = parsedNgModelAssign,
34092       pendingDebounce = null,
34093       parserValid,
34094       ctrl = this;
34095
34096   this.$$setOptions = function(options) {
34097     ctrl.$options = options;
34098     if (options && options.getterSetter) {
34099       var invokeModelGetter = $parse($attr.ngModel + '()'),
34100           invokeModelSetter = $parse($attr.ngModel + '($$$p)');
34101
34102       ngModelGet = function($scope) {
34103         var modelValue = parsedNgModel($scope);
34104         if (isFunction(modelValue)) {
34105           modelValue = invokeModelGetter($scope);
34106         }
34107         return modelValue;
34108       };
34109       ngModelSet = function($scope, newValue) {
34110         if (isFunction(parsedNgModel($scope))) {
34111           invokeModelSetter($scope, {$$$p: ctrl.$modelValue});
34112         } else {
34113           parsedNgModelAssign($scope, ctrl.$modelValue);
34114         }
34115       };
34116     } else if (!parsedNgModel.assign) {
34117       throw ngModelMinErr('nonassign', "Expression '{0}' is non-assignable. Element: {1}",
34118           $attr.ngModel, startingTag($element));
34119     }
34120   };
34121
34122   /**
34123    * @ngdoc method
34124    * @name ngModel.NgModelController#$render
34125    *
34126    * @description
34127    * Called when the view needs to be updated. It is expected that the user of the ng-model
34128    * directive will implement this method.
34129    *
34130    * The `$render()` method is invoked in the following situations:
34131    *
34132    * * `$rollbackViewValue()` is called.  If we are rolling back the view value to the last
34133    *   committed value then `$render()` is called to update the input control.
34134    * * The value referenced by `ng-model` is changed programmatically and both the `$modelValue` and
34135    *   the `$viewValue` are different from last time.
34136    *
34137    * Since `ng-model` does not do a deep watch, `$render()` is only invoked if the values of
34138    * `$modelValue` and `$viewValue` are actually different from their previous value. If `$modelValue`
34139    * or `$viewValue` are objects (rather than a string or number) then `$render()` will not be
34140    * invoked if you only change a property on the objects.
34141    */
34142   this.$render = noop;
34143
34144   /**
34145    * @ngdoc method
34146    * @name ngModel.NgModelController#$isEmpty
34147    *
34148    * @description
34149    * This is called when we need to determine if the value of an input is empty.
34150    *
34151    * For instance, the required directive does this to work out if the input has data or not.
34152    *
34153    * The default `$isEmpty` function checks whether the value is `undefined`, `''`, `null` or `NaN`.
34154    *
34155    * You can override this for input directives whose concept of being empty is different from the
34156    * default. The `checkboxInputType` directive does this because in its case a value of `false`
34157    * implies empty.
34158    *
34159    * @param {*} value The value of the input to check for emptiness.
34160    * @returns {boolean} True if `value` is "empty".
34161    */
34162   this.$isEmpty = function(value) {
34163     return isUndefined(value) || value === '' || value === null || value !== value;
34164   };
34165
34166   var currentValidationRunId = 0;
34167
34168   /**
34169    * @ngdoc method
34170    * @name ngModel.NgModelController#$setValidity
34171    *
34172    * @description
34173    * Change the validity state, and notify the form.
34174    *
34175    * This method can be called within $parsers/$formatters or a custom validation implementation.
34176    * However, in most cases it should be sufficient to use the `ngModel.$validators` and
34177    * `ngModel.$asyncValidators` collections which will call `$setValidity` automatically.
34178    *
34179    * @param {string} validationErrorKey Name of the validator. The `validationErrorKey` will be assigned
34180    *        to either `$error[validationErrorKey]` or `$pending[validationErrorKey]`
34181    *        (for unfulfilled `$asyncValidators`), so that it is available for data-binding.
34182    *        The `validationErrorKey` should be in camelCase and will get converted into dash-case
34183    *        for class name. Example: `myError` will result in `ng-valid-my-error` and `ng-invalid-my-error`
34184    *        class and can be bound to as  `{{someForm.someControl.$error.myError}}` .
34185    * @param {boolean} isValid Whether the current state is valid (true), invalid (false), pending (undefined),
34186    *                          or skipped (null). Pending is used for unfulfilled `$asyncValidators`.
34187    *                          Skipped is used by Angular when validators do not run because of parse errors and
34188    *                          when `$asyncValidators` do not run because any of the `$validators` failed.
34189    */
34190   addSetValidityMethod({
34191     ctrl: this,
34192     $element: $element,
34193     set: function(object, property) {
34194       object[property] = true;
34195     },
34196     unset: function(object, property) {
34197       delete object[property];
34198     },
34199     $animate: $animate
34200   });
34201
34202   /**
34203    * @ngdoc method
34204    * @name ngModel.NgModelController#$setPristine
34205    *
34206    * @description
34207    * Sets the control to its pristine state.
34208    *
34209    * This method can be called to remove the `ng-dirty` class and set the control to its pristine
34210    * state (`ng-pristine` class). A model is considered to be pristine when the control
34211    * has not been changed from when first compiled.
34212    */
34213   this.$setPristine = function() {
34214     ctrl.$dirty = false;
34215     ctrl.$pristine = true;
34216     $animate.removeClass($element, DIRTY_CLASS);
34217     $animate.addClass($element, PRISTINE_CLASS);
34218   };
34219
34220   /**
34221    * @ngdoc method
34222    * @name ngModel.NgModelController#$setDirty
34223    *
34224    * @description
34225    * Sets the control to its dirty state.
34226    *
34227    * This method can be called to remove the `ng-pristine` class and set the control to its dirty
34228    * state (`ng-dirty` class). A model is considered to be dirty when the control has been changed
34229    * from when first compiled.
34230    */
34231   this.$setDirty = function() {
34232     ctrl.$dirty = true;
34233     ctrl.$pristine = false;
34234     $animate.removeClass($element, PRISTINE_CLASS);
34235     $animate.addClass($element, DIRTY_CLASS);
34236     ctrl.$$parentForm.$setDirty();
34237   };
34238
34239   /**
34240    * @ngdoc method
34241    * @name ngModel.NgModelController#$setUntouched
34242    *
34243    * @description
34244    * Sets the control to its untouched state.
34245    *
34246    * This method can be called to remove the `ng-touched` class and set the control to its
34247    * untouched state (`ng-untouched` class). Upon compilation, a model is set as untouched
34248    * by default, however this function can be used to restore that state if the model has
34249    * already been touched by the user.
34250    */
34251   this.$setUntouched = function() {
34252     ctrl.$touched = false;
34253     ctrl.$untouched = true;
34254     $animate.setClass($element, UNTOUCHED_CLASS, TOUCHED_CLASS);
34255   };
34256
34257   /**
34258    * @ngdoc method
34259    * @name ngModel.NgModelController#$setTouched
34260    *
34261    * @description
34262    * Sets the control to its touched state.
34263    *
34264    * This method can be called to remove the `ng-untouched` class and set the control to its
34265    * touched state (`ng-touched` class). A model is considered to be touched when the user has
34266    * first focused the control element and then shifted focus away from the control (blur event).
34267    */
34268   this.$setTouched = function() {
34269     ctrl.$touched = true;
34270     ctrl.$untouched = false;
34271     $animate.setClass($element, TOUCHED_CLASS, UNTOUCHED_CLASS);
34272   };
34273
34274   /**
34275    * @ngdoc method
34276    * @name ngModel.NgModelController#$rollbackViewValue
34277    *
34278    * @description
34279    * Cancel an update and reset the input element's value to prevent an update to the `$modelValue`,
34280    * which may be caused by a pending debounced event or because the input is waiting for a some
34281    * future event.
34282    *
34283    * If you have an input that uses `ng-model-options` to set up debounced events or events such
34284    * as blur you can have a situation where there is a period when the `$viewValue`
34285    * is out of synch with the ngModel's `$modelValue`.
34286    *
34287    * In this case, you can run into difficulties if you try to update the ngModel's `$modelValue`
34288    * programmatically before these debounced/future events have resolved/occurred, because Angular's
34289    * dirty checking mechanism is not able to tell whether the model has actually changed or not.
34290    *
34291    * The `$rollbackViewValue()` method should be called before programmatically changing the model of an
34292    * input which may have such events pending. This is important in order to make sure that the
34293    * input field will be updated with the new model value and any pending operations are cancelled.
34294    *
34295    * <example name="ng-model-cancel-update" module="cancel-update-example">
34296    *   <file name="app.js">
34297    *     angular.module('cancel-update-example', [])
34298    *
34299    *     .controller('CancelUpdateController', ['$scope', function($scope) {
34300    *       $scope.resetWithCancel = function(e) {
34301    *         if (e.keyCode == 27) {
34302    *           $scope.myForm.myInput1.$rollbackViewValue();
34303    *           $scope.myValue = '';
34304    *         }
34305    *       };
34306    *       $scope.resetWithoutCancel = function(e) {
34307    *         if (e.keyCode == 27) {
34308    *           $scope.myValue = '';
34309    *         }
34310    *       };
34311    *     }]);
34312    *   </file>
34313    *   <file name="index.html">
34314    *     <div ng-controller="CancelUpdateController">
34315    *       <p>Try typing something in each input.  See that the model only updates when you
34316    *          blur off the input.
34317    *        </p>
34318    *        <p>Now see what happens if you start typing then press the Escape key</p>
34319    *
34320    *       <form name="myForm" ng-model-options="{ updateOn: 'blur' }">
34321    *         <p id="inputDescription1">With $rollbackViewValue()</p>
34322    *         <input name="myInput1" aria-describedby="inputDescription1" ng-model="myValue"
34323    *                ng-keydown="resetWithCancel($event)"><br/>
34324    *         myValue: "{{ myValue }}"
34325    *
34326    *         <p id="inputDescription2">Without $rollbackViewValue()</p>
34327    *         <input name="myInput2" aria-describedby="inputDescription2" ng-model="myValue"
34328    *                ng-keydown="resetWithoutCancel($event)"><br/>
34329    *         myValue: "{{ myValue }}"
34330    *       </form>
34331    *     </div>
34332    *   </file>
34333    * </example>
34334    */
34335   this.$rollbackViewValue = function() {
34336     $timeout.cancel(pendingDebounce);
34337     ctrl.$viewValue = ctrl.$$lastCommittedViewValue;
34338     ctrl.$render();
34339   };
34340
34341   /**
34342    * @ngdoc method
34343    * @name ngModel.NgModelController#$validate
34344    *
34345    * @description
34346    * Runs each of the registered validators (first synchronous validators and then
34347    * asynchronous validators).
34348    * If the validity changes to invalid, the model will be set to `undefined`,
34349    * unless {@link ngModelOptions `ngModelOptions.allowInvalid`} is `true`.
34350    * If the validity changes to valid, it will set the model to the last available valid
34351    * `$modelValue`, i.e. either the last parsed value or the last value set from the scope.
34352    */
34353   this.$validate = function() {
34354     // ignore $validate before model is initialized
34355     if (isNumber(ctrl.$modelValue) && isNaN(ctrl.$modelValue)) {
34356       return;
34357     }
34358
34359     var viewValue = ctrl.$$lastCommittedViewValue;
34360     // Note: we use the $$rawModelValue as $modelValue might have been
34361     // set to undefined during a view -> model update that found validation
34362     // errors. We can't parse the view here, since that could change
34363     // the model although neither viewValue nor the model on the scope changed
34364     var modelValue = ctrl.$$rawModelValue;
34365
34366     var prevValid = ctrl.$valid;
34367     var prevModelValue = ctrl.$modelValue;
34368
34369     var allowInvalid = ctrl.$options && ctrl.$options.allowInvalid;
34370
34371     ctrl.$$runValidators(modelValue, viewValue, function(allValid) {
34372       // If there was no change in validity, don't update the model
34373       // This prevents changing an invalid modelValue to undefined
34374       if (!allowInvalid && prevValid !== allValid) {
34375         // Note: Don't check ctrl.$valid here, as we could have
34376         // external validators (e.g. calculated on the server),
34377         // that just call $setValidity and need the model value
34378         // to calculate their validity.
34379         ctrl.$modelValue = allValid ? modelValue : undefined;
34380
34381         if (ctrl.$modelValue !== prevModelValue) {
34382           ctrl.$$writeModelToScope();
34383         }
34384       }
34385     });
34386
34387   };
34388
34389   this.$$runValidators = function(modelValue, viewValue, doneCallback) {
34390     currentValidationRunId++;
34391     var localValidationRunId = currentValidationRunId;
34392
34393     // check parser error
34394     if (!processParseErrors()) {
34395       validationDone(false);
34396       return;
34397     }
34398     if (!processSyncValidators()) {
34399       validationDone(false);
34400       return;
34401     }
34402     processAsyncValidators();
34403
34404     function processParseErrors() {
34405       var errorKey = ctrl.$$parserName || 'parse';
34406       if (isUndefined(parserValid)) {
34407         setValidity(errorKey, null);
34408       } else {
34409         if (!parserValid) {
34410           forEach(ctrl.$validators, function(v, name) {
34411             setValidity(name, null);
34412           });
34413           forEach(ctrl.$asyncValidators, function(v, name) {
34414             setValidity(name, null);
34415           });
34416         }
34417         // Set the parse error last, to prevent unsetting it, should a $validators key == parserName
34418         setValidity(errorKey, parserValid);
34419         return parserValid;
34420       }
34421       return true;
34422     }
34423
34424     function processSyncValidators() {
34425       var syncValidatorsValid = true;
34426       forEach(ctrl.$validators, function(validator, name) {
34427         var result = validator(modelValue, viewValue);
34428         syncValidatorsValid = syncValidatorsValid && result;
34429         setValidity(name, result);
34430       });
34431       if (!syncValidatorsValid) {
34432         forEach(ctrl.$asyncValidators, function(v, name) {
34433           setValidity(name, null);
34434         });
34435         return false;
34436       }
34437       return true;
34438     }
34439
34440     function processAsyncValidators() {
34441       var validatorPromises = [];
34442       var allValid = true;
34443       forEach(ctrl.$asyncValidators, function(validator, name) {
34444         var promise = validator(modelValue, viewValue);
34445         if (!isPromiseLike(promise)) {
34446           throw ngModelMinErr("$asyncValidators",
34447             "Expected asynchronous validator to return a promise but got '{0}' instead.", promise);
34448         }
34449         setValidity(name, undefined);
34450         validatorPromises.push(promise.then(function() {
34451           setValidity(name, true);
34452         }, function(error) {
34453           allValid = false;
34454           setValidity(name, false);
34455         }));
34456       });
34457       if (!validatorPromises.length) {
34458         validationDone(true);
34459       } else {
34460         $q.all(validatorPromises).then(function() {
34461           validationDone(allValid);
34462         }, noop);
34463       }
34464     }
34465
34466     function setValidity(name, isValid) {
34467       if (localValidationRunId === currentValidationRunId) {
34468         ctrl.$setValidity(name, isValid);
34469       }
34470     }
34471
34472     function validationDone(allValid) {
34473       if (localValidationRunId === currentValidationRunId) {
34474
34475         doneCallback(allValid);
34476       }
34477     }
34478   };
34479
34480   /**
34481    * @ngdoc method
34482    * @name ngModel.NgModelController#$commitViewValue
34483    *
34484    * @description
34485    * Commit a pending update to the `$modelValue`.
34486    *
34487    * Updates may be pending by a debounced event or because the input is waiting for a some future
34488    * event defined in `ng-model-options`. this method is rarely needed as `NgModelController`
34489    * usually handles calling this in response to input events.
34490    */
34491   this.$commitViewValue = function() {
34492     var viewValue = ctrl.$viewValue;
34493
34494     $timeout.cancel(pendingDebounce);
34495
34496     // If the view value has not changed then we should just exit, except in the case where there is
34497     // a native validator on the element. In this case the validation state may have changed even though
34498     // the viewValue has stayed empty.
34499     if (ctrl.$$lastCommittedViewValue === viewValue && (viewValue !== '' || !ctrl.$$hasNativeValidators)) {
34500       return;
34501     }
34502     ctrl.$$lastCommittedViewValue = viewValue;
34503
34504     // change to dirty
34505     if (ctrl.$pristine) {
34506       this.$setDirty();
34507     }
34508     this.$$parseAndValidate();
34509   };
34510
34511   this.$$parseAndValidate = function() {
34512     var viewValue = ctrl.$$lastCommittedViewValue;
34513     var modelValue = viewValue;
34514     parserValid = isUndefined(modelValue) ? undefined : true;
34515
34516     if (parserValid) {
34517       for (var i = 0; i < ctrl.$parsers.length; i++) {
34518         modelValue = ctrl.$parsers[i](modelValue);
34519         if (isUndefined(modelValue)) {
34520           parserValid = false;
34521           break;
34522         }
34523       }
34524     }
34525     if (isNumber(ctrl.$modelValue) && isNaN(ctrl.$modelValue)) {
34526       // ctrl.$modelValue has not been touched yet...
34527       ctrl.$modelValue = ngModelGet($scope);
34528     }
34529     var prevModelValue = ctrl.$modelValue;
34530     var allowInvalid = ctrl.$options && ctrl.$options.allowInvalid;
34531     ctrl.$$rawModelValue = modelValue;
34532
34533     if (allowInvalid) {
34534       ctrl.$modelValue = modelValue;
34535       writeToModelIfNeeded();
34536     }
34537
34538     // Pass the $$lastCommittedViewValue here, because the cached viewValue might be out of date.
34539     // This can happen if e.g. $setViewValue is called from inside a parser
34540     ctrl.$$runValidators(modelValue, ctrl.$$lastCommittedViewValue, function(allValid) {
34541       if (!allowInvalid) {
34542         // Note: Don't check ctrl.$valid here, as we could have
34543         // external validators (e.g. calculated on the server),
34544         // that just call $setValidity and need the model value
34545         // to calculate their validity.
34546         ctrl.$modelValue = allValid ? modelValue : undefined;
34547         writeToModelIfNeeded();
34548       }
34549     });
34550
34551     function writeToModelIfNeeded() {
34552       if (ctrl.$modelValue !== prevModelValue) {
34553         ctrl.$$writeModelToScope();
34554       }
34555     }
34556   };
34557
34558   this.$$writeModelToScope = function() {
34559     ngModelSet($scope, ctrl.$modelValue);
34560     forEach(ctrl.$viewChangeListeners, function(listener) {
34561       try {
34562         listener();
34563       } catch (e) {
34564         $exceptionHandler(e);
34565       }
34566     });
34567   };
34568
34569   /**
34570    * @ngdoc method
34571    * @name ngModel.NgModelController#$setViewValue
34572    *
34573    * @description
34574    * Update the view value.
34575    *
34576    * This method should be called when a control wants to change the view value; typically,
34577    * this is done from within a DOM event handler. For example, the {@link ng.directive:input input}
34578    * directive calls it when the value of the input changes and {@link ng.directive:select select}
34579    * calls it when an option is selected.
34580    *
34581    * When `$setViewValue` is called, the new `value` will be staged for committing through the `$parsers`
34582    * and `$validators` pipelines. If there are no special {@link ngModelOptions} specified then the staged
34583    * value sent directly for processing, finally to be applied to `$modelValue` and then the
34584    * **expression** specified in the `ng-model` attribute. Lastly, all the registered change listeners,
34585    * in the `$viewChangeListeners` list, are called.
34586    *
34587    * In case the {@link ng.directive:ngModelOptions ngModelOptions} directive is used with `updateOn`
34588    * and the `default` trigger is not listed, all those actions will remain pending until one of the
34589    * `updateOn` events is triggered on the DOM element.
34590    * All these actions will be debounced if the {@link ng.directive:ngModelOptions ngModelOptions}
34591    * directive is used with a custom debounce for this particular event.
34592    * Note that a `$digest` is only triggered once the `updateOn` events are fired, or if `debounce`
34593    * is specified, once the timer runs out.
34594    *
34595    * When used with standard inputs, the view value will always be a string (which is in some cases
34596    * parsed into another type, such as a `Date` object for `input[date]`.)
34597    * However, custom controls might also pass objects to this method. In this case, we should make
34598    * a copy of the object before passing it to `$setViewValue`. This is because `ngModel` does not
34599    * perform a deep watch of objects, it only looks for a change of identity. If you only change
34600    * the property of the object then ngModel will not realise that the object has changed and
34601    * will not invoke the `$parsers` and `$validators` pipelines. For this reason, you should
34602    * not change properties of the copy once it has been passed to `$setViewValue`.
34603    * Otherwise you may cause the model value on the scope to change incorrectly.
34604    *
34605    * <div class="alert alert-info">
34606    * In any case, the value passed to the method should always reflect the current value
34607    * of the control. For example, if you are calling `$setViewValue` for an input element,
34608    * you should pass the input DOM value. Otherwise, the control and the scope model become
34609    * out of sync. It's also important to note that `$setViewValue` does not call `$render` or change
34610    * the control's DOM value in any way. If we want to change the control's DOM value
34611    * programmatically, we should update the `ngModel` scope expression. Its new value will be
34612    * picked up by the model controller, which will run it through the `$formatters`, `$render` it
34613    * to update the DOM, and finally call `$validate` on it.
34614    * </div>
34615    *
34616    * @param {*} value value from the view.
34617    * @param {string} trigger Event that triggered the update.
34618    */
34619   this.$setViewValue = function(value, trigger) {
34620     ctrl.$viewValue = value;
34621     if (!ctrl.$options || ctrl.$options.updateOnDefault) {
34622       ctrl.$$debounceViewValueCommit(trigger);
34623     }
34624   };
34625
34626   this.$$debounceViewValueCommit = function(trigger) {
34627     var debounceDelay = 0,
34628         options = ctrl.$options,
34629         debounce;
34630
34631     if (options && isDefined(options.debounce)) {
34632       debounce = options.debounce;
34633       if (isNumber(debounce)) {
34634         debounceDelay = debounce;
34635       } else if (isNumber(debounce[trigger])) {
34636         debounceDelay = debounce[trigger];
34637       } else if (isNumber(debounce['default'])) {
34638         debounceDelay = debounce['default'];
34639       }
34640     }
34641
34642     $timeout.cancel(pendingDebounce);
34643     if (debounceDelay) {
34644       pendingDebounce = $timeout(function() {
34645         ctrl.$commitViewValue();
34646       }, debounceDelay);
34647     } else if ($rootScope.$$phase) {
34648       ctrl.$commitViewValue();
34649     } else {
34650       $scope.$apply(function() {
34651         ctrl.$commitViewValue();
34652       });
34653     }
34654   };
34655
34656   // model -> value
34657   // Note: we cannot use a normal scope.$watch as we want to detect the following:
34658   // 1. scope value is 'a'
34659   // 2. user enters 'b'
34660   // 3. ng-change kicks in and reverts scope value to 'a'
34661   //    -> scope value did not change since the last digest as
34662   //       ng-change executes in apply phase
34663   // 4. view should be changed back to 'a'
34664   $scope.$watch(function ngModelWatch() {
34665     var modelValue = ngModelGet($scope);
34666
34667     // if scope model value and ngModel value are out of sync
34668     // TODO(perf): why not move this to the action fn?
34669     if (modelValue !== ctrl.$modelValue &&
34670        // checks for NaN is needed to allow setting the model to NaN when there's an asyncValidator
34671        (ctrl.$modelValue === ctrl.$modelValue || modelValue === modelValue)
34672     ) {
34673       ctrl.$modelValue = ctrl.$$rawModelValue = modelValue;
34674       parserValid = undefined;
34675
34676       var formatters = ctrl.$formatters,
34677           idx = formatters.length;
34678
34679       var viewValue = modelValue;
34680       while (idx--) {
34681         viewValue = formatters[idx](viewValue);
34682       }
34683       if (ctrl.$viewValue !== viewValue) {
34684         ctrl.$viewValue = ctrl.$$lastCommittedViewValue = viewValue;
34685         ctrl.$render();
34686
34687         ctrl.$$runValidators(modelValue, viewValue, noop);
34688       }
34689     }
34690
34691     return modelValue;
34692   });
34693 }];
34694
34695
34696 /**
34697  * @ngdoc directive
34698  * @name ngModel
34699  *
34700  * @element input
34701  * @priority 1
34702  *
34703  * @description
34704  * The `ngModel` directive binds an `input`,`select`, `textarea` (or custom form control) to a
34705  * property on the scope using {@link ngModel.NgModelController NgModelController},
34706  * which is created and exposed by this directive.
34707  *
34708  * `ngModel` is responsible for:
34709  *
34710  * - Binding the view into the model, which other directives such as `input`, `textarea` or `select`
34711  *   require.
34712  * - Providing validation behavior (i.e. required, number, email, url).
34713  * - Keeping the state of the control (valid/invalid, dirty/pristine, touched/untouched, validation errors).
34714  * - Setting related css classes on the element (`ng-valid`, `ng-invalid`, `ng-dirty`, `ng-pristine`, `ng-touched`, `ng-untouched`) including animations.
34715  * - Registering the control with its parent {@link ng.directive:form form}.
34716  *
34717  * Note: `ngModel` will try to bind to the property given by evaluating the expression on the
34718  * current scope. If the property doesn't already exist on this scope, it will be created
34719  * implicitly and added to the scope.
34720  *
34721  * For best practices on using `ngModel`, see:
34722  *
34723  *  - [Understanding Scopes](https://github.com/angular/angular.js/wiki/Understanding-Scopes)
34724  *
34725  * For basic examples, how to use `ngModel`, see:
34726  *
34727  *  - {@link ng.directive:input input}
34728  *    - {@link input[text] text}
34729  *    - {@link input[checkbox] checkbox}
34730  *    - {@link input[radio] radio}
34731  *    - {@link input[number] number}
34732  *    - {@link input[email] email}
34733  *    - {@link input[url] url}
34734  *    - {@link input[date] date}
34735  *    - {@link input[datetime-local] datetime-local}
34736  *    - {@link input[time] time}
34737  *    - {@link input[month] month}
34738  *    - {@link input[week] week}
34739  *  - {@link ng.directive:select select}
34740  *  - {@link ng.directive:textarea textarea}
34741  *
34742  * # CSS classes
34743  * The following CSS classes are added and removed on the associated input/select/textarea element
34744  * depending on the validity of the model.
34745  *
34746  *  - `ng-valid`: the model is valid
34747  *  - `ng-invalid`: the model is invalid
34748  *  - `ng-valid-[key]`: for each valid key added by `$setValidity`
34749  *  - `ng-invalid-[key]`: for each invalid key added by `$setValidity`
34750  *  - `ng-pristine`: the control hasn't been interacted with yet
34751  *  - `ng-dirty`: the control has been interacted with
34752  *  - `ng-touched`: the control has been blurred
34753  *  - `ng-untouched`: the control hasn't been blurred
34754  *  - `ng-pending`: any `$asyncValidators` are unfulfilled
34755  *
34756  * Keep in mind that ngAnimate can detect each of these classes when added and removed.
34757  *
34758  * ## Animation Hooks
34759  *
34760  * Animations within models are triggered when any of the associated CSS classes are added and removed
34761  * on the input element which is attached to the model. These classes are: `.ng-pristine`, `.ng-dirty`,
34762  * `.ng-invalid` and `.ng-valid` as well as any other validations that are performed on the model itself.
34763  * The animations that are triggered within ngModel are similar to how they work in ngClass and
34764  * animations can be hooked into using CSS transitions, keyframes as well as JS animations.
34765  *
34766  * The following example shows a simple way to utilize CSS transitions to style an input element
34767  * that has been rendered as invalid after it has been validated:
34768  *
34769  * <pre>
34770  * //be sure to include ngAnimate as a module to hook into more
34771  * //advanced animations
34772  * .my-input {
34773  *   transition:0.5s linear all;
34774  *   background: white;
34775  * }
34776  * .my-input.ng-invalid {
34777  *   background: red;
34778  *   color:white;
34779  * }
34780  * </pre>
34781  *
34782  * @example
34783  * <example deps="angular-animate.js" animations="true" fixBase="true" module="inputExample">
34784      <file name="index.html">
34785        <script>
34786         angular.module('inputExample', [])
34787           .controller('ExampleController', ['$scope', function($scope) {
34788             $scope.val = '1';
34789           }]);
34790        </script>
34791        <style>
34792          .my-input {
34793            transition:all linear 0.5s;
34794            background: transparent;
34795          }
34796          .my-input.ng-invalid {
34797            color:white;
34798            background: red;
34799          }
34800        </style>
34801        <p id="inputDescription">
34802         Update input to see transitions when valid/invalid.
34803         Integer is a valid value.
34804        </p>
34805        <form name="testForm" ng-controller="ExampleController">
34806          <input ng-model="val" ng-pattern="/^\d+$/" name="anim" class="my-input"
34807                 aria-describedby="inputDescription" />
34808        </form>
34809      </file>
34810  * </example>
34811  *
34812  * ## Binding to a getter/setter
34813  *
34814  * Sometimes it's helpful to bind `ngModel` to a getter/setter function.  A getter/setter is a
34815  * function that returns a representation of the model when called with zero arguments, and sets
34816  * the internal state of a model when called with an argument. It's sometimes useful to use this
34817  * for models that have an internal representation that's different from what the model exposes
34818  * to the view.
34819  *
34820  * <div class="alert alert-success">
34821  * **Best Practice:** It's best to keep getters fast because Angular is likely to call them more
34822  * frequently than other parts of your code.
34823  * </div>
34824  *
34825  * You use this behavior by adding `ng-model-options="{ getterSetter: true }"` to an element that
34826  * has `ng-model` attached to it. You can also add `ng-model-options="{ getterSetter: true }"` to
34827  * a `<form>`, which will enable this behavior for all `<input>`s within it. See
34828  * {@link ng.directive:ngModelOptions `ngModelOptions`} for more.
34829  *
34830  * The following example shows how to use `ngModel` with a getter/setter:
34831  *
34832  * @example
34833  * <example name="ngModel-getter-setter" module="getterSetterExample">
34834      <file name="index.html">
34835        <div ng-controller="ExampleController">
34836          <form name="userForm">
34837            <label>Name:
34838              <input type="text" name="userName"
34839                     ng-model="user.name"
34840                     ng-model-options="{ getterSetter: true }" />
34841            </label>
34842          </form>
34843          <pre>user.name = <span ng-bind="user.name()"></span></pre>
34844        </div>
34845      </file>
34846      <file name="app.js">
34847        angular.module('getterSetterExample', [])
34848          .controller('ExampleController', ['$scope', function($scope) {
34849            var _name = 'Brian';
34850            $scope.user = {
34851              name: function(newName) {
34852               // Note that newName can be undefined for two reasons:
34853               // 1. Because it is called as a getter and thus called with no arguments
34854               // 2. Because the property should actually be set to undefined. This happens e.g. if the
34855               //    input is invalid
34856               return arguments.length ? (_name = newName) : _name;
34857              }
34858            };
34859          }]);
34860      </file>
34861  * </example>
34862  */
34863 var ngModelDirective = ['$rootScope', function($rootScope) {
34864   return {
34865     restrict: 'A',
34866     require: ['ngModel', '^?form', '^?ngModelOptions'],
34867     controller: NgModelController,
34868     // Prelink needs to run before any input directive
34869     // so that we can set the NgModelOptions in NgModelController
34870     // before anyone else uses it.
34871     priority: 1,
34872     compile: function ngModelCompile(element) {
34873       // Setup initial state of the control
34874       element.addClass(PRISTINE_CLASS).addClass(UNTOUCHED_CLASS).addClass(VALID_CLASS);
34875
34876       return {
34877         pre: function ngModelPreLink(scope, element, attr, ctrls) {
34878           var modelCtrl = ctrls[0],
34879               formCtrl = ctrls[1] || modelCtrl.$$parentForm;
34880
34881           modelCtrl.$$setOptions(ctrls[2] && ctrls[2].$options);
34882
34883           // notify others, especially parent forms
34884           formCtrl.$addControl(modelCtrl);
34885
34886           attr.$observe('name', function(newValue) {
34887             if (modelCtrl.$name !== newValue) {
34888               modelCtrl.$$parentForm.$$renameControl(modelCtrl, newValue);
34889             }
34890           });
34891
34892           scope.$on('$destroy', function() {
34893             modelCtrl.$$parentForm.$removeControl(modelCtrl);
34894           });
34895         },
34896         post: function ngModelPostLink(scope, element, attr, ctrls) {
34897           var modelCtrl = ctrls[0];
34898           if (modelCtrl.$options && modelCtrl.$options.updateOn) {
34899             element.on(modelCtrl.$options.updateOn, function(ev) {
34900               modelCtrl.$$debounceViewValueCommit(ev && ev.type);
34901             });
34902           }
34903
34904           element.on('blur', function(ev) {
34905             if (modelCtrl.$touched) return;
34906
34907             if ($rootScope.$$phase) {
34908               scope.$evalAsync(modelCtrl.$setTouched);
34909             } else {
34910               scope.$apply(modelCtrl.$setTouched);
34911             }
34912           });
34913         }
34914       };
34915     }
34916   };
34917 }];
34918
34919 var DEFAULT_REGEXP = /(\s+|^)default(\s+|$)/;
34920
34921 /**
34922  * @ngdoc directive
34923  * @name ngModelOptions
34924  *
34925  * @description
34926  * Allows tuning how model updates are done. Using `ngModelOptions` you can specify a custom list of
34927  * events that will trigger a model update and/or a debouncing delay so that the actual update only
34928  * takes place when a timer expires; this timer will be reset after another change takes place.
34929  *
34930  * Given the nature of `ngModelOptions`, the value displayed inside input fields in the view might
34931  * be different from the value in the actual model. This means that if you update the model you
34932  * should also invoke {@link ngModel.NgModelController `$rollbackViewValue`} on the relevant input field in
34933  * order to make sure it is synchronized with the model and that any debounced action is canceled.
34934  *
34935  * The easiest way to reference the control's {@link ngModel.NgModelController `$rollbackViewValue`}
34936  * method is by making sure the input is placed inside a form that has a `name` attribute. This is
34937  * important because `form` controllers are published to the related scope under the name in their
34938  * `name` attribute.
34939  *
34940  * Any pending changes will take place immediately when an enclosing form is submitted via the
34941  * `submit` event. Note that `ngClick` events will occur before the model is updated. Use `ngSubmit`
34942  * to have access to the updated model.
34943  *
34944  * `ngModelOptions` has an effect on the element it's declared on and its descendants.
34945  *
34946  * @param {Object} ngModelOptions options to apply to the current model. Valid keys are:
34947  *   - `updateOn`: string specifying which event should the input be bound to. You can set several
34948  *     events using an space delimited list. There is a special event called `default` that
34949  *     matches the default events belonging of the control.
34950  *   - `debounce`: integer value which contains the debounce model update value in milliseconds. A
34951  *     value of 0 triggers an immediate update. If an object is supplied instead, you can specify a
34952  *     custom value for each event. For example:
34953  *     `ng-model-options="{ updateOn: 'default blur', debounce: { 'default': 500, 'blur': 0 } }"`
34954  *   - `allowInvalid`: boolean value which indicates that the model can be set with values that did
34955  *     not validate correctly instead of the default behavior of setting the model to undefined.
34956  *   - `getterSetter`: boolean value which determines whether or not to treat functions bound to
34957        `ngModel` as getters/setters.
34958  *   - `timezone`: Defines the timezone to be used to read/write the `Date` instance in the model for
34959  *     `<input type="date">`, `<input type="time">`, ... . It understands UTC/GMT and the
34960  *     continental US time zone abbreviations, but for general use, use a time zone offset, for
34961  *     example, `'+0430'` (4 hours, 30 minutes east of the Greenwich meridian)
34962  *     If not specified, the timezone of the browser will be used.
34963  *
34964  * @example
34965
34966   The following example shows how to override immediate updates. Changes on the inputs within the
34967   form will update the model only when the control loses focus (blur event). If `escape` key is
34968   pressed while the input field is focused, the value is reset to the value in the current model.
34969
34970   <example name="ngModelOptions-directive-blur" module="optionsExample">
34971     <file name="index.html">
34972       <div ng-controller="ExampleController">
34973         <form name="userForm">
34974           <label>Name:
34975             <input type="text" name="userName"
34976                    ng-model="user.name"
34977                    ng-model-options="{ updateOn: 'blur' }"
34978                    ng-keyup="cancel($event)" />
34979           </label><br />
34980           <label>Other data:
34981             <input type="text" ng-model="user.data" />
34982           </label><br />
34983         </form>
34984         <pre>user.name = <span ng-bind="user.name"></span></pre>
34985         <pre>user.data = <span ng-bind="user.data"></span></pre>
34986       </div>
34987     </file>
34988     <file name="app.js">
34989       angular.module('optionsExample', [])
34990         .controller('ExampleController', ['$scope', function($scope) {
34991           $scope.user = { name: 'John', data: '' };
34992
34993           $scope.cancel = function(e) {
34994             if (e.keyCode == 27) {
34995               $scope.userForm.userName.$rollbackViewValue();
34996             }
34997           };
34998         }]);
34999     </file>
35000     <file name="protractor.js" type="protractor">
35001       var model = element(by.binding('user.name'));
35002       var input = element(by.model('user.name'));
35003       var other = element(by.model('user.data'));
35004
35005       it('should allow custom events', function() {
35006         input.sendKeys(' Doe');
35007         input.click();
35008         expect(model.getText()).toEqual('John');
35009         other.click();
35010         expect(model.getText()).toEqual('John Doe');
35011       });
35012
35013       it('should $rollbackViewValue when model changes', function() {
35014         input.sendKeys(' Doe');
35015         expect(input.getAttribute('value')).toEqual('John Doe');
35016         input.sendKeys(protractor.Key.ESCAPE);
35017         expect(input.getAttribute('value')).toEqual('John');
35018         other.click();
35019         expect(model.getText()).toEqual('John');
35020       });
35021     </file>
35022   </example>
35023
35024   This one shows how to debounce model changes. Model will be updated only 1 sec after last change.
35025   If the `Clear` button is pressed, any debounced action is canceled and the value becomes empty.
35026
35027   <example name="ngModelOptions-directive-debounce" module="optionsExample">
35028     <file name="index.html">
35029       <div ng-controller="ExampleController">
35030         <form name="userForm">
35031           <label>Name:
35032             <input type="text" name="userName"
35033                    ng-model="user.name"
35034                    ng-model-options="{ debounce: 1000 }" />
35035           </label>
35036           <button ng-click="userForm.userName.$rollbackViewValue(); user.name=''">Clear</button>
35037           <br />
35038         </form>
35039         <pre>user.name = <span ng-bind="user.name"></span></pre>
35040       </div>
35041     </file>
35042     <file name="app.js">
35043       angular.module('optionsExample', [])
35044         .controller('ExampleController', ['$scope', function($scope) {
35045           $scope.user = { name: 'Igor' };
35046         }]);
35047     </file>
35048   </example>
35049
35050   This one shows how to bind to getter/setters:
35051
35052   <example name="ngModelOptions-directive-getter-setter" module="getterSetterExample">
35053     <file name="index.html">
35054       <div ng-controller="ExampleController">
35055         <form name="userForm">
35056           <label>Name:
35057             <input type="text" name="userName"
35058                    ng-model="user.name"
35059                    ng-model-options="{ getterSetter: true }" />
35060           </label>
35061         </form>
35062         <pre>user.name = <span ng-bind="user.name()"></span></pre>
35063       </div>
35064     </file>
35065     <file name="app.js">
35066       angular.module('getterSetterExample', [])
35067         .controller('ExampleController', ['$scope', function($scope) {
35068           var _name = 'Brian';
35069           $scope.user = {
35070             name: function(newName) {
35071               // Note that newName can be undefined for two reasons:
35072               // 1. Because it is called as a getter and thus called with no arguments
35073               // 2. Because the property should actually be set to undefined. This happens e.g. if the
35074               //    input is invalid
35075               return arguments.length ? (_name = newName) : _name;
35076             }
35077           };
35078         }]);
35079     </file>
35080   </example>
35081  */
35082 var ngModelOptionsDirective = function() {
35083   return {
35084     restrict: 'A',
35085     controller: ['$scope', '$attrs', function($scope, $attrs) {
35086       var that = this;
35087       this.$options = copy($scope.$eval($attrs.ngModelOptions));
35088       // Allow adding/overriding bound events
35089       if (isDefined(this.$options.updateOn)) {
35090         this.$options.updateOnDefault = false;
35091         // extract "default" pseudo-event from list of events that can trigger a model update
35092         this.$options.updateOn = trim(this.$options.updateOn.replace(DEFAULT_REGEXP, function() {
35093           that.$options.updateOnDefault = true;
35094           return ' ';
35095         }));
35096       } else {
35097         this.$options.updateOnDefault = true;
35098       }
35099     }]
35100   };
35101 };
35102
35103
35104
35105 // helper methods
35106 function addSetValidityMethod(context) {
35107   var ctrl = context.ctrl,
35108       $element = context.$element,
35109       classCache = {},
35110       set = context.set,
35111       unset = context.unset,
35112       $animate = context.$animate;
35113
35114   classCache[INVALID_CLASS] = !(classCache[VALID_CLASS] = $element.hasClass(VALID_CLASS));
35115
35116   ctrl.$setValidity = setValidity;
35117
35118   function setValidity(validationErrorKey, state, controller) {
35119     if (isUndefined(state)) {
35120       createAndSet('$pending', validationErrorKey, controller);
35121     } else {
35122       unsetAndCleanup('$pending', validationErrorKey, controller);
35123     }
35124     if (!isBoolean(state)) {
35125       unset(ctrl.$error, validationErrorKey, controller);
35126       unset(ctrl.$$success, validationErrorKey, controller);
35127     } else {
35128       if (state) {
35129         unset(ctrl.$error, validationErrorKey, controller);
35130         set(ctrl.$$success, validationErrorKey, controller);
35131       } else {
35132         set(ctrl.$error, validationErrorKey, controller);
35133         unset(ctrl.$$success, validationErrorKey, controller);
35134       }
35135     }
35136     if (ctrl.$pending) {
35137       cachedToggleClass(PENDING_CLASS, true);
35138       ctrl.$valid = ctrl.$invalid = undefined;
35139       toggleValidationCss('', null);
35140     } else {
35141       cachedToggleClass(PENDING_CLASS, false);
35142       ctrl.$valid = isObjectEmpty(ctrl.$error);
35143       ctrl.$invalid = !ctrl.$valid;
35144       toggleValidationCss('', ctrl.$valid);
35145     }
35146
35147     // re-read the state as the set/unset methods could have
35148     // combined state in ctrl.$error[validationError] (used for forms),
35149     // where setting/unsetting only increments/decrements the value,
35150     // and does not replace it.
35151     var combinedState;
35152     if (ctrl.$pending && ctrl.$pending[validationErrorKey]) {
35153       combinedState = undefined;
35154     } else if (ctrl.$error[validationErrorKey]) {
35155       combinedState = false;
35156     } else if (ctrl.$$success[validationErrorKey]) {
35157       combinedState = true;
35158     } else {
35159       combinedState = null;
35160     }
35161
35162     toggleValidationCss(validationErrorKey, combinedState);
35163     ctrl.$$parentForm.$setValidity(validationErrorKey, combinedState, ctrl);
35164   }
35165
35166   function createAndSet(name, value, controller) {
35167     if (!ctrl[name]) {
35168       ctrl[name] = {};
35169     }
35170     set(ctrl[name], value, controller);
35171   }
35172
35173   function unsetAndCleanup(name, value, controller) {
35174     if (ctrl[name]) {
35175       unset(ctrl[name], value, controller);
35176     }
35177     if (isObjectEmpty(ctrl[name])) {
35178       ctrl[name] = undefined;
35179     }
35180   }
35181
35182   function cachedToggleClass(className, switchValue) {
35183     if (switchValue && !classCache[className]) {
35184       $animate.addClass($element, className);
35185       classCache[className] = true;
35186     } else if (!switchValue && classCache[className]) {
35187       $animate.removeClass($element, className);
35188       classCache[className] = false;
35189     }
35190   }
35191
35192   function toggleValidationCss(validationErrorKey, isValid) {
35193     validationErrorKey = validationErrorKey ? '-' + snake_case(validationErrorKey, '-') : '';
35194
35195     cachedToggleClass(VALID_CLASS + validationErrorKey, isValid === true);
35196     cachedToggleClass(INVALID_CLASS + validationErrorKey, isValid === false);
35197   }
35198 }
35199
35200 function isObjectEmpty(obj) {
35201   if (obj) {
35202     for (var prop in obj) {
35203       if (obj.hasOwnProperty(prop)) {
35204         return false;
35205       }
35206     }
35207   }
35208   return true;
35209 }
35210
35211 /**
35212  * @ngdoc directive
35213  * @name ngNonBindable
35214  * @restrict AC
35215  * @priority 1000
35216  *
35217  * @description
35218  * The `ngNonBindable` directive tells Angular not to compile or bind the contents of the current
35219  * DOM element. This is useful if the element contains what appears to be Angular directives and
35220  * bindings but which should be ignored by Angular. This could be the case if you have a site that
35221  * displays snippets of code, for instance.
35222  *
35223  * @element ANY
35224  *
35225  * @example
35226  * In this example there are two locations where a simple interpolation binding (`{{}}`) is present,
35227  * but the one wrapped in `ngNonBindable` is left alone.
35228  *
35229  * @example
35230     <example>
35231       <file name="index.html">
35232         <div>Normal: {{1 + 2}}</div>
35233         <div ng-non-bindable>Ignored: {{1 + 2}}</div>
35234       </file>
35235       <file name="protractor.js" type="protractor">
35236        it('should check ng-non-bindable', function() {
35237          expect(element(by.binding('1 + 2')).getText()).toContain('3');
35238          expect(element.all(by.css('div')).last().getText()).toMatch(/1 \+ 2/);
35239        });
35240       </file>
35241     </example>
35242  */
35243 var ngNonBindableDirective = ngDirective({ terminal: true, priority: 1000 });
35244
35245 /* global jqLiteRemove */
35246
35247 var ngOptionsMinErr = minErr('ngOptions');
35248
35249 /**
35250  * @ngdoc directive
35251  * @name ngOptions
35252  * @restrict A
35253  *
35254  * @description
35255  *
35256  * The `ngOptions` attribute can be used to dynamically generate a list of `<option>`
35257  * elements for the `<select>` element using the array or object obtained by evaluating the
35258  * `ngOptions` comprehension expression.
35259  *
35260  * In many cases, `ngRepeat` can be used on `<option>` elements instead of `ngOptions` to achieve a
35261  * similar result. However, `ngOptions` provides some benefits such as reducing memory and
35262  * increasing speed by not creating a new scope for each repeated instance, as well as providing
35263  * more flexibility in how the `<select>`'s model is assigned via the `select` **`as`** part of the
35264  * comprehension expression. `ngOptions` should be used when the `<select>` model needs to be bound
35265  *  to a non-string value. This is because an option element can only be bound to string values at
35266  * present.
35267  *
35268  * When an item in the `<select>` menu is selected, the array element or object property
35269  * represented by the selected option will be bound to the model identified by the `ngModel`
35270  * directive.
35271  *
35272  * Optionally, a single hard-coded `<option>` element, with the value set to an empty string, can
35273  * be nested into the `<select>` element. This element will then represent the `null` or "not selected"
35274  * option. See example below for demonstration.
35275  *
35276  * ## Complex Models (objects or collections)
35277  *
35278  * By default, `ngModel` watches the model by reference, not value. This is important to know when
35279  * binding the select to a model that is an object or a collection.
35280  *
35281  * One issue occurs if you want to preselect an option. For example, if you set
35282  * the model to an object that is equal to an object in your collection, `ngOptions` won't be able to set the selection,
35283  * because the objects are not identical. So by default, you should always reference the item in your collection
35284  * for preselections, e.g.: `$scope.selected = $scope.collection[3]`.
35285  *
35286  * Another solution is to use a `track by` clause, because then `ngOptions` will track the identity
35287  * of the item not by reference, but by the result of the `track by` expression. For example, if your
35288  * collection items have an id property, you would `track by item.id`.
35289  *
35290  * A different issue with objects or collections is that ngModel won't detect if an object property or
35291  * a collection item changes. For that reason, `ngOptions` additionally watches the model using
35292  * `$watchCollection`, when the expression contains a `track by` clause or the the select has the `multiple` attribute.
35293  * This allows ngOptions to trigger a re-rendering of the options even if the actual object/collection
35294  * has not changed identity, but only a property on the object or an item in the collection changes.
35295  *
35296  * Note that `$watchCollection` does a shallow comparison of the properties of the object (or the items in the collection
35297  * if the model is an array). This means that changing a property deeper than the first level inside the
35298  * object/collection will not trigger a re-rendering.
35299  *
35300  * ## `select` **`as`**
35301  *
35302  * Using `select` **`as`** will bind the result of the `select` expression to the model, but
35303  * the value of the `<select>` and `<option>` html elements will be either the index (for array data sources)
35304  * or property name (for object data sources) of the value within the collection. If a **`track by`** expression
35305  * is used, the result of that expression will be set as the value of the `option` and `select` elements.
35306  *
35307  *
35308  * ### `select` **`as`** and **`track by`**
35309  *
35310  * <div class="alert alert-warning">
35311  * Be careful when using `select` **`as`** and **`track by`** in the same expression.
35312  * </div>
35313  *
35314  * Given this array of items on the $scope:
35315  *
35316  * ```js
35317  * $scope.items = [{
35318  *   id: 1,
35319  *   label: 'aLabel',
35320  *   subItem: { name: 'aSubItem' }
35321  * }, {
35322  *   id: 2,
35323  *   label: 'bLabel',
35324  *   subItem: { name: 'bSubItem' }
35325  * }];
35326  * ```
35327  *
35328  * This will work:
35329  *
35330  * ```html
35331  * <select ng-options="item as item.label for item in items track by item.id" ng-model="selected"></select>
35332  * ```
35333  * ```js
35334  * $scope.selected = $scope.items[0];
35335  * ```
35336  *
35337  * but this will not work:
35338  *
35339  * ```html
35340  * <select ng-options="item.subItem as item.label for item in items track by item.id" ng-model="selected"></select>
35341  * ```
35342  * ```js
35343  * $scope.selected = $scope.items[0].subItem;
35344  * ```
35345  *
35346  * In both examples, the **`track by`** expression is applied successfully to each `item` in the
35347  * `items` array. Because the selected option has been set programmatically in the controller, the
35348  * **`track by`** expression is also applied to the `ngModel` value. In the first example, the
35349  * `ngModel` value is `items[0]` and the **`track by`** expression evaluates to `items[0].id` with
35350  * no issue. In the second example, the `ngModel` value is `items[0].subItem` and the **`track by`**
35351  * expression evaluates to `items[0].subItem.id` (which is undefined). As a result, the model value
35352  * is not matched against any `<option>` and the `<select>` appears as having no selected value.
35353  *
35354  *
35355  * @param {string} ngModel Assignable angular expression to data-bind to.
35356  * @param {string=} name Property name of the form under which the control is published.
35357  * @param {string=} required The control is considered valid only if value is entered.
35358  * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
35359  *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
35360  *    `required` when you want to data-bind to the `required` attribute.
35361  * @param {comprehension_expression=} ngOptions in one of the following forms:
35362  *
35363  *   * for array data sources:
35364  *     * `label` **`for`** `value` **`in`** `array`
35365  *     * `select` **`as`** `label` **`for`** `value` **`in`** `array`
35366  *     * `label` **`group by`** `group` **`for`** `value` **`in`** `array`
35367  *     * `label` **`disable when`** `disable` **`for`** `value` **`in`** `array`
35368  *     * `label` **`group by`** `group` **`for`** `value` **`in`** `array` **`track by`** `trackexpr`
35369  *     * `label` **`disable when`** `disable` **`for`** `value` **`in`** `array` **`track by`** `trackexpr`
35370  *     * `label` **`for`** `value` **`in`** `array` | orderBy:`orderexpr` **`track by`** `trackexpr`
35371  *        (for including a filter with `track by`)
35372  *   * for object data sources:
35373  *     * `label` **`for (`**`key` **`,`** `value`**`) in`** `object`
35374  *     * `select` **`as`** `label` **`for (`**`key` **`,`** `value`**`) in`** `object`
35375  *     * `label` **`group by`** `group` **`for (`**`key`**`,`** `value`**`) in`** `object`
35376  *     * `label` **`disable when`** `disable` **`for (`**`key`**`,`** `value`**`) in`** `object`
35377  *     * `select` **`as`** `label` **`group by`** `group`
35378  *         **`for` `(`**`key`**`,`** `value`**`) in`** `object`
35379  *     * `select` **`as`** `label` **`disable when`** `disable`
35380  *         **`for` `(`**`key`**`,`** `value`**`) in`** `object`
35381  *
35382  * Where:
35383  *
35384  *   * `array` / `object`: an expression which evaluates to an array / object to iterate over.
35385  *   * `value`: local variable which will refer to each item in the `array` or each property value
35386  *      of `object` during iteration.
35387  *   * `key`: local variable which will refer to a property name in `object` during iteration.
35388  *   * `label`: The result of this expression will be the label for `<option>` element. The
35389  *     `expression` will most likely refer to the `value` variable (e.g. `value.propertyName`).
35390  *   * `select`: The result of this expression will be bound to the model of the parent `<select>`
35391  *      element. If not specified, `select` expression will default to `value`.
35392  *   * `group`: The result of this expression will be used to group options using the `<optgroup>`
35393  *      DOM element.
35394  *   * `disable`: The result of this expression will be used to disable the rendered `<option>`
35395  *      element. Return `true` to disable.
35396  *   * `trackexpr`: Used when working with an array of objects. The result of this expression will be
35397  *      used to identify the objects in the array. The `trackexpr` will most likely refer to the
35398  *     `value` variable (e.g. `value.propertyName`). With this the selection is preserved
35399  *      even when the options are recreated (e.g. reloaded from the server).
35400  *
35401  * @example
35402     <example module="selectExample">
35403       <file name="index.html">
35404         <script>
35405         angular.module('selectExample', [])
35406           .controller('ExampleController', ['$scope', function($scope) {
35407             $scope.colors = [
35408               {name:'black', shade:'dark'},
35409               {name:'white', shade:'light', notAnOption: true},
35410               {name:'red', shade:'dark'},
35411               {name:'blue', shade:'dark', notAnOption: true},
35412               {name:'yellow', shade:'light', notAnOption: false}
35413             ];
35414             $scope.myColor = $scope.colors[2]; // red
35415           }]);
35416         </script>
35417         <div ng-controller="ExampleController">
35418           <ul>
35419             <li ng-repeat="color in colors">
35420               <label>Name: <input ng-model="color.name"></label>
35421               <label><input type="checkbox" ng-model="color.notAnOption"> Disabled?</label>
35422               <button ng-click="colors.splice($index, 1)" aria-label="Remove">X</button>
35423             </li>
35424             <li>
35425               <button ng-click="colors.push({})">add</button>
35426             </li>
35427           </ul>
35428           <hr/>
35429           <label>Color (null not allowed):
35430             <select ng-model="myColor" ng-options="color.name for color in colors"></select>
35431           </label><br/>
35432           <label>Color (null allowed):
35433           <span  class="nullable">
35434             <select ng-model="myColor" ng-options="color.name for color in colors">
35435               <option value="">-- choose color --</option>
35436             </select>
35437           </span></label><br/>
35438
35439           <label>Color grouped by shade:
35440             <select ng-model="myColor" ng-options="color.name group by color.shade for color in colors">
35441             </select>
35442           </label><br/>
35443
35444           <label>Color grouped by shade, with some disabled:
35445             <select ng-model="myColor"
35446                   ng-options="color.name group by color.shade disable when color.notAnOption for color in colors">
35447             </select>
35448           </label><br/>
35449
35450
35451
35452           Select <button ng-click="myColor = { name:'not in list', shade: 'other' }">bogus</button>.
35453           <br/>
35454           <hr/>
35455           Currently selected: {{ {selected_color:myColor} }}
35456           <div style="border:solid 1px black; height:20px"
35457                ng-style="{'background-color':myColor.name}">
35458           </div>
35459         </div>
35460       </file>
35461       <file name="protractor.js" type="protractor">
35462          it('should check ng-options', function() {
35463            expect(element(by.binding('{selected_color:myColor}')).getText()).toMatch('red');
35464            element.all(by.model('myColor')).first().click();
35465            element.all(by.css('select[ng-model="myColor"] option')).first().click();
35466            expect(element(by.binding('{selected_color:myColor}')).getText()).toMatch('black');
35467            element(by.css('.nullable select[ng-model="myColor"]')).click();
35468            element.all(by.css('.nullable select[ng-model="myColor"] option')).first().click();
35469            expect(element(by.binding('{selected_color:myColor}')).getText()).toMatch('null');
35470          });
35471       </file>
35472     </example>
35473  */
35474
35475 // jshint maxlen: false
35476 //                     //00001111111111000000000002222222222000000000000000000000333333333300000000000000000000000004444444444400000000000005555555555555550000000006666666666666660000000777777777777777000000000000000888888888800000000000000000009999999999
35477 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]+?))?$/;
35478                         // 1: value expression (valueFn)
35479                         // 2: label expression (displayFn)
35480                         // 3: group by expression (groupByFn)
35481                         // 4: disable when expression (disableWhenFn)
35482                         // 5: array item variable name
35483                         // 6: object item key variable name
35484                         // 7: object item value variable name
35485                         // 8: collection expression
35486                         // 9: track by expression
35487 // jshint maxlen: 100
35488
35489
35490 var ngOptionsDirective = ['$compile', '$parse', function($compile, $parse) {
35491
35492   function parseOptionsExpression(optionsExp, selectElement, scope) {
35493
35494     var match = optionsExp.match(NG_OPTIONS_REGEXP);
35495     if (!(match)) {
35496       throw ngOptionsMinErr('iexp',
35497         "Expected expression in form of " +
35498         "'_select_ (as _label_)? for (_key_,)?_value_ in _collection_'" +
35499         " but got '{0}'. Element: {1}",
35500         optionsExp, startingTag(selectElement));
35501     }
35502
35503     // Extract the parts from the ngOptions expression
35504
35505     // The variable name for the value of the item in the collection
35506     var valueName = match[5] || match[7];
35507     // The variable name for the key of the item in the collection
35508     var keyName = match[6];
35509
35510     // An expression that generates the viewValue for an option if there is a label expression
35511     var selectAs = / as /.test(match[0]) && match[1];
35512     // An expression that is used to track the id of each object in the options collection
35513     var trackBy = match[9];
35514     // An expression that generates the viewValue for an option if there is no label expression
35515     var valueFn = $parse(match[2] ? match[1] : valueName);
35516     var selectAsFn = selectAs && $parse(selectAs);
35517     var viewValueFn = selectAsFn || valueFn;
35518     var trackByFn = trackBy && $parse(trackBy);
35519
35520     // Get the value by which we are going to track the option
35521     // if we have a trackFn then use that (passing scope and locals)
35522     // otherwise just hash the given viewValue
35523     var getTrackByValueFn = trackBy ?
35524                               function(value, locals) { return trackByFn(scope, locals); } :
35525                               function getHashOfValue(value) { return hashKey(value); };
35526     var getTrackByValue = function(value, key) {
35527       return getTrackByValueFn(value, getLocals(value, key));
35528     };
35529
35530     var displayFn = $parse(match[2] || match[1]);
35531     var groupByFn = $parse(match[3] || '');
35532     var disableWhenFn = $parse(match[4] || '');
35533     var valuesFn = $parse(match[8]);
35534
35535     var locals = {};
35536     var getLocals = keyName ? function(value, key) {
35537       locals[keyName] = key;
35538       locals[valueName] = value;
35539       return locals;
35540     } : function(value) {
35541       locals[valueName] = value;
35542       return locals;
35543     };
35544
35545
35546     function Option(selectValue, viewValue, label, group, disabled) {
35547       this.selectValue = selectValue;
35548       this.viewValue = viewValue;
35549       this.label = label;
35550       this.group = group;
35551       this.disabled = disabled;
35552     }
35553
35554     function getOptionValuesKeys(optionValues) {
35555       var optionValuesKeys;
35556
35557       if (!keyName && isArrayLike(optionValues)) {
35558         optionValuesKeys = optionValues;
35559       } else {
35560         // if object, extract keys, in enumeration order, unsorted
35561         optionValuesKeys = [];
35562         for (var itemKey in optionValues) {
35563           if (optionValues.hasOwnProperty(itemKey) && itemKey.charAt(0) !== '$') {
35564             optionValuesKeys.push(itemKey);
35565           }
35566         }
35567       }
35568       return optionValuesKeys;
35569     }
35570
35571     return {
35572       trackBy: trackBy,
35573       getTrackByValue: getTrackByValue,
35574       getWatchables: $parse(valuesFn, function(optionValues) {
35575         // Create a collection of things that we would like to watch (watchedArray)
35576         // so that they can all be watched using a single $watchCollection
35577         // that only runs the handler once if anything changes
35578         var watchedArray = [];
35579         optionValues = optionValues || [];
35580
35581         var optionValuesKeys = getOptionValuesKeys(optionValues);
35582         var optionValuesLength = optionValuesKeys.length;
35583         for (var index = 0; index < optionValuesLength; index++) {
35584           var key = (optionValues === optionValuesKeys) ? index : optionValuesKeys[index];
35585           var value = optionValues[key];
35586
35587           var locals = getLocals(optionValues[key], key);
35588           var selectValue = getTrackByValueFn(optionValues[key], locals);
35589           watchedArray.push(selectValue);
35590
35591           // Only need to watch the displayFn if there is a specific label expression
35592           if (match[2] || match[1]) {
35593             var label = displayFn(scope, locals);
35594             watchedArray.push(label);
35595           }
35596
35597           // Only need to watch the disableWhenFn if there is a specific disable expression
35598           if (match[4]) {
35599             var disableWhen = disableWhenFn(scope, locals);
35600             watchedArray.push(disableWhen);
35601           }
35602         }
35603         return watchedArray;
35604       }),
35605
35606       getOptions: function() {
35607
35608         var optionItems = [];
35609         var selectValueMap = {};
35610
35611         // The option values were already computed in the `getWatchables` fn,
35612         // which must have been called to trigger `getOptions`
35613         var optionValues = valuesFn(scope) || [];
35614         var optionValuesKeys = getOptionValuesKeys(optionValues);
35615         var optionValuesLength = optionValuesKeys.length;
35616
35617         for (var index = 0; index < optionValuesLength; index++) {
35618           var key = (optionValues === optionValuesKeys) ? index : optionValuesKeys[index];
35619           var value = optionValues[key];
35620           var locals = getLocals(value, key);
35621           var viewValue = viewValueFn(scope, locals);
35622           var selectValue = getTrackByValueFn(viewValue, locals);
35623           var label = displayFn(scope, locals);
35624           var group = groupByFn(scope, locals);
35625           var disabled = disableWhenFn(scope, locals);
35626           var optionItem = new Option(selectValue, viewValue, label, group, disabled);
35627
35628           optionItems.push(optionItem);
35629           selectValueMap[selectValue] = optionItem;
35630         }
35631
35632         return {
35633           items: optionItems,
35634           selectValueMap: selectValueMap,
35635           getOptionFromViewValue: function(value) {
35636             return selectValueMap[getTrackByValue(value)];
35637           },
35638           getViewValueFromOption: function(option) {
35639             // If the viewValue could be an object that may be mutated by the application,
35640             // we need to make a copy and not return the reference to the value on the option.
35641             return trackBy ? angular.copy(option.viewValue) : option.viewValue;
35642           }
35643         };
35644       }
35645     };
35646   }
35647
35648
35649   // we can't just jqLite('<option>') since jqLite is not smart enough
35650   // to create it in <select> and IE barfs otherwise.
35651   var optionTemplate = document.createElement('option'),
35652       optGroupTemplate = document.createElement('optgroup');
35653
35654
35655     function ngOptionsPostLink(scope, selectElement, attr, ctrls) {
35656
35657       // if ngModel is not defined, we don't need to do anything
35658       var ngModelCtrl = ctrls[1];
35659       if (!ngModelCtrl) return;
35660
35661       var selectCtrl = ctrls[0];
35662       var multiple = attr.multiple;
35663
35664       // The emptyOption allows the application developer to provide their own custom "empty"
35665       // option when the viewValue does not match any of the option values.
35666       var emptyOption;
35667       for (var i = 0, children = selectElement.children(), ii = children.length; i < ii; i++) {
35668         if (children[i].value === '') {
35669           emptyOption = children.eq(i);
35670           break;
35671         }
35672       }
35673
35674       var providedEmptyOption = !!emptyOption;
35675
35676       var unknownOption = jqLite(optionTemplate.cloneNode(false));
35677       unknownOption.val('?');
35678
35679       var options;
35680       var ngOptions = parseOptionsExpression(attr.ngOptions, selectElement, scope);
35681
35682
35683       var renderEmptyOption = function() {
35684         if (!providedEmptyOption) {
35685           selectElement.prepend(emptyOption);
35686         }
35687         selectElement.val('');
35688         emptyOption.prop('selected', true); // needed for IE
35689         emptyOption.attr('selected', true);
35690       };
35691
35692       var removeEmptyOption = function() {
35693         if (!providedEmptyOption) {
35694           emptyOption.remove();
35695         }
35696       };
35697
35698
35699       var renderUnknownOption = function() {
35700         selectElement.prepend(unknownOption);
35701         selectElement.val('?');
35702         unknownOption.prop('selected', true); // needed for IE
35703         unknownOption.attr('selected', true);
35704       };
35705
35706       var removeUnknownOption = function() {
35707         unknownOption.remove();
35708       };
35709
35710       // Update the controller methods for multiple selectable options
35711       if (!multiple) {
35712
35713         selectCtrl.writeValue = function writeNgOptionsValue(value) {
35714           var option = options.getOptionFromViewValue(value);
35715
35716           if (option && !option.disabled) {
35717             if (selectElement[0].value !== option.selectValue) {
35718               removeUnknownOption();
35719               removeEmptyOption();
35720
35721               selectElement[0].value = option.selectValue;
35722               option.element.selected = true;
35723               option.element.setAttribute('selected', 'selected');
35724             }
35725           } else {
35726             if (value === null || providedEmptyOption) {
35727               removeUnknownOption();
35728               renderEmptyOption();
35729             } else {
35730               removeEmptyOption();
35731               renderUnknownOption();
35732             }
35733           }
35734         };
35735
35736         selectCtrl.readValue = function readNgOptionsValue() {
35737
35738           var selectedOption = options.selectValueMap[selectElement.val()];
35739
35740           if (selectedOption && !selectedOption.disabled) {
35741             removeEmptyOption();
35742             removeUnknownOption();
35743             return options.getViewValueFromOption(selectedOption);
35744           }
35745           return null;
35746         };
35747
35748         // If we are using `track by` then we must watch the tracked value on the model
35749         // since ngModel only watches for object identity change
35750         if (ngOptions.trackBy) {
35751           scope.$watch(
35752             function() { return ngOptions.getTrackByValue(ngModelCtrl.$viewValue); },
35753             function() { ngModelCtrl.$render(); }
35754           );
35755         }
35756
35757       } else {
35758
35759         ngModelCtrl.$isEmpty = function(value) {
35760           return !value || value.length === 0;
35761         };
35762
35763
35764         selectCtrl.writeValue = function writeNgOptionsMultiple(value) {
35765           options.items.forEach(function(option) {
35766             option.element.selected = false;
35767           });
35768
35769           if (value) {
35770             value.forEach(function(item) {
35771               var option = options.getOptionFromViewValue(item);
35772               if (option && !option.disabled) option.element.selected = true;
35773             });
35774           }
35775         };
35776
35777
35778         selectCtrl.readValue = function readNgOptionsMultiple() {
35779           var selectedValues = selectElement.val() || [],
35780               selections = [];
35781
35782           forEach(selectedValues, function(value) {
35783             var option = options.selectValueMap[value];
35784             if (option && !option.disabled) selections.push(options.getViewValueFromOption(option));
35785           });
35786
35787           return selections;
35788         };
35789
35790         // If we are using `track by` then we must watch these tracked values on the model
35791         // since ngModel only watches for object identity change
35792         if (ngOptions.trackBy) {
35793
35794           scope.$watchCollection(function() {
35795             if (isArray(ngModelCtrl.$viewValue)) {
35796               return ngModelCtrl.$viewValue.map(function(value) {
35797                 return ngOptions.getTrackByValue(value);
35798               });
35799             }
35800           }, function() {
35801             ngModelCtrl.$render();
35802           });
35803
35804         }
35805       }
35806
35807
35808       if (providedEmptyOption) {
35809
35810         // we need to remove it before calling selectElement.empty() because otherwise IE will
35811         // remove the label from the element. wtf?
35812         emptyOption.remove();
35813
35814         // compile the element since there might be bindings in it
35815         $compile(emptyOption)(scope);
35816
35817         // remove the class, which is added automatically because we recompile the element and it
35818         // becomes the compilation root
35819         emptyOption.removeClass('ng-scope');
35820       } else {
35821         emptyOption = jqLite(optionTemplate.cloneNode(false));
35822       }
35823
35824       // We need to do this here to ensure that the options object is defined
35825       // when we first hit it in writeNgOptionsValue
35826       updateOptions();
35827
35828       // We will re-render the option elements if the option values or labels change
35829       scope.$watchCollection(ngOptions.getWatchables, updateOptions);
35830
35831       // ------------------------------------------------------------------ //
35832
35833
35834       function updateOptionElement(option, element) {
35835         option.element = element;
35836         element.disabled = option.disabled;
35837         // NOTE: The label must be set before the value, otherwise IE10/11/EDGE create unresponsive
35838         // selects in certain circumstances when multiple selects are next to each other and display
35839         // the option list in listbox style, i.e. the select is [multiple], or specifies a [size].
35840         // See https://github.com/angular/angular.js/issues/11314 for more info.
35841         // This is unfortunately untestable with unit / e2e tests
35842         if (option.label !== element.label) {
35843           element.label = option.label;
35844           element.textContent = option.label;
35845         }
35846         if (option.value !== element.value) element.value = option.selectValue;
35847       }
35848
35849       function addOrReuseElement(parent, current, type, templateElement) {
35850         var element;
35851         // Check whether we can reuse the next element
35852         if (current && lowercase(current.nodeName) === type) {
35853           // The next element is the right type so reuse it
35854           element = current;
35855         } else {
35856           // The next element is not the right type so create a new one
35857           element = templateElement.cloneNode(false);
35858           if (!current) {
35859             // There are no more elements so just append it to the select
35860             parent.appendChild(element);
35861           } else {
35862             // The next element is not a group so insert the new one
35863             parent.insertBefore(element, current);
35864           }
35865         }
35866         return element;
35867       }
35868
35869
35870       function removeExcessElements(current) {
35871         var next;
35872         while (current) {
35873           next = current.nextSibling;
35874           jqLiteRemove(current);
35875           current = next;
35876         }
35877       }
35878
35879
35880       function skipEmptyAndUnknownOptions(current) {
35881         var emptyOption_ = emptyOption && emptyOption[0];
35882         var unknownOption_ = unknownOption && unknownOption[0];
35883
35884         // We cannot rely on the extracted empty option being the same as the compiled empty option,
35885         // because the compiled empty option might have been replaced by a comment because
35886         // it had an "element" transclusion directive on it (such as ngIf)
35887         if (emptyOption_ || unknownOption_) {
35888           while (current &&
35889                 (current === emptyOption_ ||
35890                 current === unknownOption_ ||
35891                 current.nodeType === NODE_TYPE_COMMENT ||
35892                 current.value === '')) {
35893             current = current.nextSibling;
35894           }
35895         }
35896         return current;
35897       }
35898
35899
35900       function updateOptions() {
35901
35902         var previousValue = options && selectCtrl.readValue();
35903
35904         options = ngOptions.getOptions();
35905
35906         var groupMap = {};
35907         var currentElement = selectElement[0].firstChild;
35908
35909         // Ensure that the empty option is always there if it was explicitly provided
35910         if (providedEmptyOption) {
35911           selectElement.prepend(emptyOption);
35912         }
35913
35914         currentElement = skipEmptyAndUnknownOptions(currentElement);
35915
35916         options.items.forEach(function updateOption(option) {
35917           var group;
35918           var groupElement;
35919           var optionElement;
35920
35921           if (option.group) {
35922
35923             // This option is to live in a group
35924             // See if we have already created this group
35925             group = groupMap[option.group];
35926
35927             if (!group) {
35928
35929               // We have not already created this group
35930               groupElement = addOrReuseElement(selectElement[0],
35931                                                currentElement,
35932                                                'optgroup',
35933                                                optGroupTemplate);
35934               // Move to the next element
35935               currentElement = groupElement.nextSibling;
35936
35937               // Update the label on the group element
35938               groupElement.label = option.group;
35939
35940               // Store it for use later
35941               group = groupMap[option.group] = {
35942                 groupElement: groupElement,
35943                 currentOptionElement: groupElement.firstChild
35944               };
35945
35946             }
35947
35948             // So now we have a group for this option we add the option to the group
35949             optionElement = addOrReuseElement(group.groupElement,
35950                                               group.currentOptionElement,
35951                                               'option',
35952                                               optionTemplate);
35953             updateOptionElement(option, optionElement);
35954             // Move to the next element
35955             group.currentOptionElement = optionElement.nextSibling;
35956
35957           } else {
35958
35959             // This option is not in a group
35960             optionElement = addOrReuseElement(selectElement[0],
35961                                               currentElement,
35962                                               'option',
35963                                               optionTemplate);
35964             updateOptionElement(option, optionElement);
35965             // Move to the next element
35966             currentElement = optionElement.nextSibling;
35967           }
35968         });
35969
35970
35971         // Now remove all excess options and group
35972         Object.keys(groupMap).forEach(function(key) {
35973           removeExcessElements(groupMap[key].currentOptionElement);
35974         });
35975         removeExcessElements(currentElement);
35976
35977         ngModelCtrl.$render();
35978
35979         // Check to see if the value has changed due to the update to the options
35980         if (!ngModelCtrl.$isEmpty(previousValue)) {
35981           var nextValue = selectCtrl.readValue();
35982           if (ngOptions.trackBy ? !equals(previousValue, nextValue) : previousValue !== nextValue) {
35983             ngModelCtrl.$setViewValue(nextValue);
35984             ngModelCtrl.$render();
35985           }
35986         }
35987
35988       }
35989   }
35990
35991   return {
35992     restrict: 'A',
35993     terminal: true,
35994     require: ['select', '?ngModel'],
35995     link: {
35996       pre: function ngOptionsPreLink(scope, selectElement, attr, ctrls) {
35997         // Deactivate the SelectController.register method to prevent
35998         // option directives from accidentally registering themselves
35999         // (and unwanted $destroy handlers etc.)
36000         ctrls[0].registerOption = noop;
36001       },
36002       post: ngOptionsPostLink
36003     }
36004   };
36005 }];
36006
36007 /**
36008  * @ngdoc directive
36009  * @name ngPluralize
36010  * @restrict EA
36011  *
36012  * @description
36013  * `ngPluralize` is a directive that displays messages according to en-US localization rules.
36014  * These rules are bundled with angular.js, but can be overridden
36015  * (see {@link guide/i18n Angular i18n} dev guide). You configure ngPluralize directive
36016  * by specifying the mappings between
36017  * [plural categories](http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html)
36018  * and the strings to be displayed.
36019  *
36020  * # Plural categories and explicit number rules
36021  * There are two
36022  * [plural categories](http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html)
36023  * in Angular's default en-US locale: "one" and "other".
36024  *
36025  * While a plural category may match many numbers (for example, in en-US locale, "other" can match
36026  * any number that is not 1), an explicit number rule can only match one number. For example, the
36027  * explicit number rule for "3" matches the number 3. There are examples of plural categories
36028  * and explicit number rules throughout the rest of this documentation.
36029  *
36030  * # Configuring ngPluralize
36031  * You configure ngPluralize by providing 2 attributes: `count` and `when`.
36032  * You can also provide an optional attribute, `offset`.
36033  *
36034  * The value of the `count` attribute can be either a string or an {@link guide/expression
36035  * Angular expression}; these are evaluated on the current scope for its bound value.
36036  *
36037  * The `when` attribute specifies the mappings between plural categories and the actual
36038  * string to be displayed. The value of the attribute should be a JSON object.
36039  *
36040  * The following example shows how to configure ngPluralize:
36041  *
36042  * ```html
36043  * <ng-pluralize count="personCount"
36044                  when="{'0': 'Nobody is viewing.',
36045  *                      'one': '1 person is viewing.',
36046  *                      'other': '{} people are viewing.'}">
36047  * </ng-pluralize>
36048  *```
36049  *
36050  * In the example, `"0: Nobody is viewing."` is an explicit number rule. If you did not
36051  * specify this rule, 0 would be matched to the "other" category and "0 people are viewing"
36052  * would be shown instead of "Nobody is viewing". You can specify an explicit number rule for
36053  * other numbers, for example 12, so that instead of showing "12 people are viewing", you can
36054  * show "a dozen people are viewing".
36055  *
36056  * You can use a set of closed braces (`{}`) as a placeholder for the number that you want substituted
36057  * into pluralized strings. In the previous example, Angular will replace `{}` with
36058  * <span ng-non-bindable>`{{personCount}}`</span>. The closed braces `{}` is a placeholder
36059  * for <span ng-non-bindable>{{numberExpression}}</span>.
36060  *
36061  * If no rule is defined for a category, then an empty string is displayed and a warning is generated.
36062  * Note that some locales define more categories than `one` and `other`. For example, fr-fr defines `few` and `many`.
36063  *
36064  * # Configuring ngPluralize with offset
36065  * The `offset` attribute allows further customization of pluralized text, which can result in
36066  * a better user experience. For example, instead of the message "4 people are viewing this document",
36067  * you might display "John, Kate and 2 others are viewing this document".
36068  * The offset attribute allows you to offset a number by any desired value.
36069  * Let's take a look at an example:
36070  *
36071  * ```html
36072  * <ng-pluralize count="personCount" offset=2
36073  *               when="{'0': 'Nobody is viewing.',
36074  *                      '1': '{{person1}} is viewing.',
36075  *                      '2': '{{person1}} and {{person2}} are viewing.',
36076  *                      'one': '{{person1}}, {{person2}} and one other person are viewing.',
36077  *                      'other': '{{person1}}, {{person2}} and {} other people are viewing.'}">
36078  * </ng-pluralize>
36079  * ```
36080  *
36081  * Notice that we are still using two plural categories(one, other), but we added
36082  * three explicit number rules 0, 1 and 2.
36083  * When one person, perhaps John, views the document, "John is viewing" will be shown.
36084  * When three people view the document, no explicit number rule is found, so
36085  * an offset of 2 is taken off 3, and Angular uses 1 to decide the plural category.
36086  * In this case, plural category 'one' is matched and "John, Mary and one other person are viewing"
36087  * is shown.
36088  *
36089  * Note that when you specify offsets, you must provide explicit number rules for
36090  * numbers from 0 up to and including the offset. If you use an offset of 3, for example,
36091  * you must provide explicit number rules for 0, 1, 2 and 3. You must also provide plural strings for
36092  * plural categories "one" and "other".
36093  *
36094  * @param {string|expression} count The variable to be bound to.
36095  * @param {string} when The mapping between plural category to its corresponding strings.
36096  * @param {number=} offset Offset to deduct from the total number.
36097  *
36098  * @example
36099     <example module="pluralizeExample">
36100       <file name="index.html">
36101         <script>
36102           angular.module('pluralizeExample', [])
36103             .controller('ExampleController', ['$scope', function($scope) {
36104               $scope.person1 = 'Igor';
36105               $scope.person2 = 'Misko';
36106               $scope.personCount = 1;
36107             }]);
36108         </script>
36109         <div ng-controller="ExampleController">
36110           <label>Person 1:<input type="text" ng-model="person1" value="Igor" /></label><br/>
36111           <label>Person 2:<input type="text" ng-model="person2" value="Misko" /></label><br/>
36112           <label>Number of People:<input type="text" ng-model="personCount" value="1" /></label><br/>
36113
36114           <!--- Example with simple pluralization rules for en locale --->
36115           Without Offset:
36116           <ng-pluralize count="personCount"
36117                         when="{'0': 'Nobody is viewing.',
36118                                'one': '1 person is viewing.',
36119                                'other': '{} people are viewing.'}">
36120           </ng-pluralize><br>
36121
36122           <!--- Example with offset --->
36123           With Offset(2):
36124           <ng-pluralize count="personCount" offset=2
36125                         when="{'0': 'Nobody is viewing.',
36126                                '1': '{{person1}} is viewing.',
36127                                '2': '{{person1}} and {{person2}} are viewing.',
36128                                'one': '{{person1}}, {{person2}} and one other person are viewing.',
36129                                'other': '{{person1}}, {{person2}} and {} other people are viewing.'}">
36130           </ng-pluralize>
36131         </div>
36132       </file>
36133       <file name="protractor.js" type="protractor">
36134         it('should show correct pluralized string', function() {
36135           var withoutOffset = element.all(by.css('ng-pluralize')).get(0);
36136           var withOffset = element.all(by.css('ng-pluralize')).get(1);
36137           var countInput = element(by.model('personCount'));
36138
36139           expect(withoutOffset.getText()).toEqual('1 person is viewing.');
36140           expect(withOffset.getText()).toEqual('Igor is viewing.');
36141
36142           countInput.clear();
36143           countInput.sendKeys('0');
36144
36145           expect(withoutOffset.getText()).toEqual('Nobody is viewing.');
36146           expect(withOffset.getText()).toEqual('Nobody is viewing.');
36147
36148           countInput.clear();
36149           countInput.sendKeys('2');
36150
36151           expect(withoutOffset.getText()).toEqual('2 people are viewing.');
36152           expect(withOffset.getText()).toEqual('Igor and Misko are viewing.');
36153
36154           countInput.clear();
36155           countInput.sendKeys('3');
36156
36157           expect(withoutOffset.getText()).toEqual('3 people are viewing.');
36158           expect(withOffset.getText()).toEqual('Igor, Misko and one other person are viewing.');
36159
36160           countInput.clear();
36161           countInput.sendKeys('4');
36162
36163           expect(withoutOffset.getText()).toEqual('4 people are viewing.');
36164           expect(withOffset.getText()).toEqual('Igor, Misko and 2 other people are viewing.');
36165         });
36166         it('should show data-bound names', function() {
36167           var withOffset = element.all(by.css('ng-pluralize')).get(1);
36168           var personCount = element(by.model('personCount'));
36169           var person1 = element(by.model('person1'));
36170           var person2 = element(by.model('person2'));
36171           personCount.clear();
36172           personCount.sendKeys('4');
36173           person1.clear();
36174           person1.sendKeys('Di');
36175           person2.clear();
36176           person2.sendKeys('Vojta');
36177           expect(withOffset.getText()).toEqual('Di, Vojta and 2 other people are viewing.');
36178         });
36179       </file>
36180     </example>
36181  */
36182 var ngPluralizeDirective = ['$locale', '$interpolate', '$log', function($locale, $interpolate, $log) {
36183   var BRACE = /{}/g,
36184       IS_WHEN = /^when(Minus)?(.+)$/;
36185
36186   return {
36187     link: function(scope, element, attr) {
36188       var numberExp = attr.count,
36189           whenExp = attr.$attr.when && element.attr(attr.$attr.when), // we have {{}} in attrs
36190           offset = attr.offset || 0,
36191           whens = scope.$eval(whenExp) || {},
36192           whensExpFns = {},
36193           startSymbol = $interpolate.startSymbol(),
36194           endSymbol = $interpolate.endSymbol(),
36195           braceReplacement = startSymbol + numberExp + '-' + offset + endSymbol,
36196           watchRemover = angular.noop,
36197           lastCount;
36198
36199       forEach(attr, function(expression, attributeName) {
36200         var tmpMatch = IS_WHEN.exec(attributeName);
36201         if (tmpMatch) {
36202           var whenKey = (tmpMatch[1] ? '-' : '') + lowercase(tmpMatch[2]);
36203           whens[whenKey] = element.attr(attr.$attr[attributeName]);
36204         }
36205       });
36206       forEach(whens, function(expression, key) {
36207         whensExpFns[key] = $interpolate(expression.replace(BRACE, braceReplacement));
36208
36209       });
36210
36211       scope.$watch(numberExp, function ngPluralizeWatchAction(newVal) {
36212         var count = parseFloat(newVal);
36213         var countIsNaN = isNaN(count);
36214
36215         if (!countIsNaN && !(count in whens)) {
36216           // If an explicit number rule such as 1, 2, 3... is defined, just use it.
36217           // Otherwise, check it against pluralization rules in $locale service.
36218           count = $locale.pluralCat(count - offset);
36219         }
36220
36221         // If both `count` and `lastCount` are NaN, we don't need to re-register a watch.
36222         // In JS `NaN !== NaN`, so we have to exlicitly check.
36223         if ((count !== lastCount) && !(countIsNaN && isNumber(lastCount) && isNaN(lastCount))) {
36224           watchRemover();
36225           var whenExpFn = whensExpFns[count];
36226           if (isUndefined(whenExpFn)) {
36227             if (newVal != null) {
36228               $log.debug("ngPluralize: no rule defined for '" + count + "' in " + whenExp);
36229             }
36230             watchRemover = noop;
36231             updateElementText();
36232           } else {
36233             watchRemover = scope.$watch(whenExpFn, updateElementText);
36234           }
36235           lastCount = count;
36236         }
36237       });
36238
36239       function updateElementText(newText) {
36240         element.text(newText || '');
36241       }
36242     }
36243   };
36244 }];
36245
36246 /**
36247  * @ngdoc directive
36248  * @name ngRepeat
36249  * @multiElement
36250  *
36251  * @description
36252  * The `ngRepeat` directive instantiates a template once per item from a collection. Each template
36253  * instance gets its own scope, where the given loop variable is set to the current collection item,
36254  * and `$index` is set to the item index or key.
36255  *
36256  * Special properties are exposed on the local scope of each template instance, including:
36257  *
36258  * | Variable  | Type            | Details                                                                     |
36259  * |-----------|-----------------|-----------------------------------------------------------------------------|
36260  * | `$index`  | {@type number}  | iterator offset of the repeated element (0..length-1)                       |
36261  * | `$first`  | {@type boolean} | true if the repeated element is first in the iterator.                      |
36262  * | `$middle` | {@type boolean} | true if the repeated element is between the first and last in the iterator. |
36263  * | `$last`   | {@type boolean} | true if the repeated element is last in the iterator.                       |
36264  * | `$even`   | {@type boolean} | true if the iterator position `$index` is even (otherwise false).           |
36265  * | `$odd`    | {@type boolean} | true if the iterator position `$index` is odd (otherwise false).            |
36266  *
36267  * <div class="alert alert-info">
36268  *   Creating aliases for these properties is possible with {@link ng.directive:ngInit `ngInit`}.
36269  *   This may be useful when, for instance, nesting ngRepeats.
36270  * </div>
36271  *
36272  *
36273  * # Iterating over object properties
36274  *
36275  * It is possible to get `ngRepeat` to iterate over the properties of an object using the following
36276  * syntax:
36277  *
36278  * ```js
36279  * <div ng-repeat="(key, value) in myObj"> ... </div>
36280  * ```
36281  *
36282  * You need to be aware that the JavaScript specification does not define the order of keys
36283  * returned for an object. (To mitigate this in Angular 1.3 the `ngRepeat` directive
36284  * used to sort the keys alphabetically.)
36285  *
36286  * Version 1.4 removed the alphabetic sorting. We now rely on the order returned by the browser
36287  * when running `for key in myObj`. It seems that browsers generally follow the strategy of providing
36288  * keys in the order in which they were defined, although there are exceptions when keys are deleted
36289  * 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).
36290  *
36291  * If this is not desired, the recommended workaround is to convert your object into an array
36292  * that is sorted into the order that you prefer before providing it to `ngRepeat`.  You could
36293  * do this with a filter such as [toArrayFilter](http://ngmodules.org/modules/angular-toArrayFilter)
36294  * or implement a `$watch` on the object yourself.
36295  *
36296  *
36297  * # Tracking and Duplicates
36298  *
36299  * `ngRepeat` uses {@link $rootScope.Scope#$watchCollection $watchCollection} to detect changes in
36300  * the collection. When a change happens, ngRepeat then makes the corresponding changes to the DOM:
36301  *
36302  * * When an item is added, a new instance of the template is added to the DOM.
36303  * * When an item is removed, its template instance is removed from the DOM.
36304  * * When items are reordered, their respective templates are reordered in the DOM.
36305  *
36306  * To minimize creation of DOM elements, `ngRepeat` uses a function
36307  * to "keep track" of all items in the collection and their corresponding DOM elements.
36308  * For example, if an item is added to the collection, ngRepeat will know that all other items
36309  * already have DOM elements, and will not re-render them.
36310  *
36311  * The default tracking function (which tracks items by their identity) does not allow
36312  * duplicate items in arrays. This is because when there are duplicates, it is not possible
36313  * to maintain a one-to-one mapping between collection items and DOM elements.
36314  *
36315  * If you do need to repeat duplicate items, you can substitute the default tracking behavior
36316  * with your own using the `track by` expression.
36317  *
36318  * For example, you may track items by the index of each item in the collection, using the
36319  * special scope property `$index`:
36320  * ```html
36321  *    <div ng-repeat="n in [42, 42, 43, 43] track by $index">
36322  *      {{n}}
36323  *    </div>
36324  * ```
36325  *
36326  * You may also use arbitrary expressions in `track by`, including references to custom functions
36327  * on the scope:
36328  * ```html
36329  *    <div ng-repeat="n in [42, 42, 43, 43] track by myTrackingFunction(n)">
36330  *      {{n}}
36331  *    </div>
36332  * ```
36333  *
36334  * <div class="alert alert-success">
36335  * If you are working with objects that have an identifier property, you should track
36336  * by the identifier instead of the whole object. Should you reload your data later, `ngRepeat`
36337  * will not have to rebuild the DOM elements for items it has already rendered, even if the
36338  * JavaScript objects in the collection have been substituted for new ones. For large collections,
36339  * this signifincantly improves rendering performance. If you don't have a unique identifier,
36340  * `track by $index` can also provide a performance boost.
36341  * </div>
36342  * ```html
36343  *    <div ng-repeat="model in collection track by model.id">
36344  *      {{model.name}}
36345  *    </div>
36346  * ```
36347  *
36348  * When no `track by` expression is provided, it is equivalent to tracking by the built-in
36349  * `$id` function, which tracks items by their identity:
36350  * ```html
36351  *    <div ng-repeat="obj in collection track by $id(obj)">
36352  *      {{obj.prop}}
36353  *    </div>
36354  * ```
36355  *
36356  * <div class="alert alert-warning">
36357  * **Note:** `track by` must always be the last expression:
36358  * </div>
36359  * ```
36360  * <div ng-repeat="model in collection | orderBy: 'id' as filtered_result track by model.id">
36361  *     {{model.name}}
36362  * </div>
36363  * ```
36364  *
36365  * # Special repeat start and end points
36366  * To repeat a series of elements instead of just one parent element, ngRepeat (as well as other ng directives) supports extending
36367  * the range of the repeater by defining explicit start and end points by using **ng-repeat-start** and **ng-repeat-end** respectively.
36368  * 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)
36369  * up to and including the ending HTML tag where **ng-repeat-end** is placed.
36370  *
36371  * The example below makes use of this feature:
36372  * ```html
36373  *   <header ng-repeat-start="item in items">
36374  *     Header {{ item }}
36375  *   </header>
36376  *   <div class="body">
36377  *     Body {{ item }}
36378  *   </div>
36379  *   <footer ng-repeat-end>
36380  *     Footer {{ item }}
36381  *   </footer>
36382  * ```
36383  *
36384  * And with an input of {@type ['A','B']} for the items variable in the example above, the output will evaluate to:
36385  * ```html
36386  *   <header>
36387  *     Header A
36388  *   </header>
36389  *   <div class="body">
36390  *     Body A
36391  *   </div>
36392  *   <footer>
36393  *     Footer A
36394  *   </footer>
36395  *   <header>
36396  *     Header B
36397  *   </header>
36398  *   <div class="body">
36399  *     Body B
36400  *   </div>
36401  *   <footer>
36402  *     Footer B
36403  *   </footer>
36404  * ```
36405  *
36406  * The custom start and end points for ngRepeat also support all other HTML directive syntax flavors provided in AngularJS (such
36407  * as **data-ng-repeat-start**, **x-ng-repeat-start** and **ng:repeat-start**).
36408  *
36409  * @animations
36410  * **.enter** - when a new item is added to the list or when an item is revealed after a filter
36411  *
36412  * **.leave** - when an item is removed from the list or when an item is filtered out
36413  *
36414  * **.move** - when an adjacent item is filtered out causing a reorder or when the item contents are reordered
36415  *
36416  * @element ANY
36417  * @scope
36418  * @priority 1000
36419  * @param {repeat_expression} ngRepeat The expression indicating how to enumerate a collection. These
36420  *   formats are currently supported:
36421  *
36422  *   * `variable in expression` – where variable is the user defined loop variable and `expression`
36423  *     is a scope expression giving the collection to enumerate.
36424  *
36425  *     For example: `album in artist.albums`.
36426  *
36427  *   * `(key, value) in expression` – where `key` and `value` can be any user defined identifiers,
36428  *     and `expression` is the scope expression giving the collection to enumerate.
36429  *
36430  *     For example: `(name, age) in {'adam':10, 'amalie':12}`.
36431  *
36432  *   * `variable in expression track by tracking_expression` – You can also provide an optional tracking expression
36433  *     which can be used to associate the objects in the collection with the DOM elements. If no tracking expression
36434  *     is specified, ng-repeat associates elements by identity. It is an error to have
36435  *     more than one tracking expression value resolve to the same key. (This would mean that two distinct objects are
36436  *     mapped to the same DOM element, which is not possible.)
36437  *
36438  *     Note that the tracking expression must come last, after any filters, and the alias expression.
36439  *
36440  *     For example: `item in items` is equivalent to `item in items track by $id(item)`. This implies that the DOM elements
36441  *     will be associated by item identity in the array.
36442  *
36443  *     For example: `item in items track by $id(item)`. A built in `$id()` function can be used to assign a unique
36444  *     `$$hashKey` property to each item in the array. This property is then used as a key to associated DOM elements
36445  *     with the corresponding item in the array by identity. Moving the same object in array would move the DOM
36446  *     element in the same way in the DOM.
36447  *
36448  *     For example: `item in items track by item.id` is a typical pattern when the items come from the database. In this
36449  *     case the object identity does not matter. Two objects are considered equivalent as long as their `id`
36450  *     property is same.
36451  *
36452  *     For example: `item in items | filter:searchText track by item.id` is a pattern that might be used to apply a filter
36453  *     to items in conjunction with a tracking expression.
36454  *
36455  *   * `variable in expression as alias_expression` – You can also provide an optional alias expression which will then store the
36456  *     intermediate results of the repeater after the filters have been applied. Typically this is used to render a special message
36457  *     when a filter is active on the repeater, but the filtered result set is empty.
36458  *
36459  *     For example: `item in items | filter:x as results` will store the fragment of the repeated items as `results`, but only after
36460  *     the items have been processed through the filter.
36461  *
36462  *     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
36463  *     (and not as operator, inside an expression).
36464  *
36465  *     For example: `item in items | filter : x | orderBy : order | limitTo : limit as results` .
36466  *
36467  * @example
36468  * This example initializes the scope to a list of names and
36469  * then uses `ngRepeat` to display every person:
36470   <example module="ngAnimate" deps="angular-animate.js" animations="true">
36471     <file name="index.html">
36472       <div ng-init="friends = [
36473         {name:'John', age:25, gender:'boy'},
36474         {name:'Jessie', age:30, gender:'girl'},
36475         {name:'Johanna', age:28, gender:'girl'},
36476         {name:'Joy', age:15, gender:'girl'},
36477         {name:'Mary', age:28, gender:'girl'},
36478         {name:'Peter', age:95, gender:'boy'},
36479         {name:'Sebastian', age:50, gender:'boy'},
36480         {name:'Erika', age:27, gender:'girl'},
36481         {name:'Patrick', age:40, gender:'boy'},
36482         {name:'Samantha', age:60, gender:'girl'}
36483       ]">
36484         I have {{friends.length}} friends. They are:
36485         <input type="search" ng-model="q" placeholder="filter friends..." aria-label="filter friends" />
36486         <ul class="example-animate-container">
36487           <li class="animate-repeat" ng-repeat="friend in friends | filter:q as results">
36488             [{{$index + 1}}] {{friend.name}} who is {{friend.age}} years old.
36489           </li>
36490           <li class="animate-repeat" ng-if="results.length == 0">
36491             <strong>No results found...</strong>
36492           </li>
36493         </ul>
36494       </div>
36495     </file>
36496     <file name="animations.css">
36497       .example-animate-container {
36498         background:white;
36499         border:1px solid black;
36500         list-style:none;
36501         margin:0;
36502         padding:0 10px;
36503       }
36504
36505       .animate-repeat {
36506         line-height:40px;
36507         list-style:none;
36508         box-sizing:border-box;
36509       }
36510
36511       .animate-repeat.ng-move,
36512       .animate-repeat.ng-enter,
36513       .animate-repeat.ng-leave {
36514         transition:all linear 0.5s;
36515       }
36516
36517       .animate-repeat.ng-leave.ng-leave-active,
36518       .animate-repeat.ng-move,
36519       .animate-repeat.ng-enter {
36520         opacity:0;
36521         max-height:0;
36522       }
36523
36524       .animate-repeat.ng-leave,
36525       .animate-repeat.ng-move.ng-move-active,
36526       .animate-repeat.ng-enter.ng-enter-active {
36527         opacity:1;
36528         max-height:40px;
36529       }
36530     </file>
36531     <file name="protractor.js" type="protractor">
36532       var friends = element.all(by.repeater('friend in friends'));
36533
36534       it('should render initial data set', function() {
36535         expect(friends.count()).toBe(10);
36536         expect(friends.get(0).getText()).toEqual('[1] John who is 25 years old.');
36537         expect(friends.get(1).getText()).toEqual('[2] Jessie who is 30 years old.');
36538         expect(friends.last().getText()).toEqual('[10] Samantha who is 60 years old.');
36539         expect(element(by.binding('friends.length')).getText())
36540             .toMatch("I have 10 friends. They are:");
36541       });
36542
36543        it('should update repeater when filter predicate changes', function() {
36544          expect(friends.count()).toBe(10);
36545
36546          element(by.model('q')).sendKeys('ma');
36547
36548          expect(friends.count()).toBe(2);
36549          expect(friends.get(0).getText()).toEqual('[1] Mary who is 28 years old.');
36550          expect(friends.last().getText()).toEqual('[2] Samantha who is 60 years old.');
36551        });
36552       </file>
36553     </example>
36554  */
36555 var ngRepeatDirective = ['$parse', '$animate', function($parse, $animate) {
36556   var NG_REMOVED = '$$NG_REMOVED';
36557   var ngRepeatMinErr = minErr('ngRepeat');
36558
36559   var updateScope = function(scope, index, valueIdentifier, value, keyIdentifier, key, arrayLength) {
36560     // TODO(perf): generate setters to shave off ~40ms or 1-1.5%
36561     scope[valueIdentifier] = value;
36562     if (keyIdentifier) scope[keyIdentifier] = key;
36563     scope.$index = index;
36564     scope.$first = (index === 0);
36565     scope.$last = (index === (arrayLength - 1));
36566     scope.$middle = !(scope.$first || scope.$last);
36567     // jshint bitwise: false
36568     scope.$odd = !(scope.$even = (index&1) === 0);
36569     // jshint bitwise: true
36570   };
36571
36572   var getBlockStart = function(block) {
36573     return block.clone[0];
36574   };
36575
36576   var getBlockEnd = function(block) {
36577     return block.clone[block.clone.length - 1];
36578   };
36579
36580
36581   return {
36582     restrict: 'A',
36583     multiElement: true,
36584     transclude: 'element',
36585     priority: 1000,
36586     terminal: true,
36587     $$tlb: true,
36588     compile: function ngRepeatCompile($element, $attr) {
36589       var expression = $attr.ngRepeat;
36590       var ngRepeatEndComment = document.createComment(' end ngRepeat: ' + expression + ' ');
36591
36592       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*$/);
36593
36594       if (!match) {
36595         throw ngRepeatMinErr('iexp', "Expected expression in form of '_item_ in _collection_[ track by _id_]' but got '{0}'.",
36596             expression);
36597       }
36598
36599       var lhs = match[1];
36600       var rhs = match[2];
36601       var aliasAs = match[3];
36602       var trackByExp = match[4];
36603
36604       match = lhs.match(/^(?:(\s*[\$\w]+)|\(\s*([\$\w]+)\s*,\s*([\$\w]+)\s*\))$/);
36605
36606       if (!match) {
36607         throw ngRepeatMinErr('iidexp', "'_item_' in '_item_ in _collection_' should be an identifier or '(_key_, _value_)' expression, but got '{0}'.",
36608             lhs);
36609       }
36610       var valueIdentifier = match[3] || match[1];
36611       var keyIdentifier = match[2];
36612
36613       if (aliasAs && (!/^[$a-zA-Z_][$a-zA-Z0-9_]*$/.test(aliasAs) ||
36614           /^(null|undefined|this|\$index|\$first|\$middle|\$last|\$even|\$odd|\$parent|\$root|\$id)$/.test(aliasAs))) {
36615         throw ngRepeatMinErr('badident', "alias '{0}' is invalid --- must be a valid JS identifier which is not a reserved name.",
36616           aliasAs);
36617       }
36618
36619       var trackByExpGetter, trackByIdExpFn, trackByIdArrayFn, trackByIdObjFn;
36620       var hashFnLocals = {$id: hashKey};
36621
36622       if (trackByExp) {
36623         trackByExpGetter = $parse(trackByExp);
36624       } else {
36625         trackByIdArrayFn = function(key, value) {
36626           return hashKey(value);
36627         };
36628         trackByIdObjFn = function(key) {
36629           return key;
36630         };
36631       }
36632
36633       return function ngRepeatLink($scope, $element, $attr, ctrl, $transclude) {
36634
36635         if (trackByExpGetter) {
36636           trackByIdExpFn = function(key, value, index) {
36637             // assign key, value, and $index to the locals so that they can be used in hash functions
36638             if (keyIdentifier) hashFnLocals[keyIdentifier] = key;
36639             hashFnLocals[valueIdentifier] = value;
36640             hashFnLocals.$index = index;
36641             return trackByExpGetter($scope, hashFnLocals);
36642           };
36643         }
36644
36645         // Store a list of elements from previous run. This is a hash where key is the item from the
36646         // iterator, and the value is objects with following properties.
36647         //   - scope: bound scope
36648         //   - element: previous element.
36649         //   - index: position
36650         //
36651         // We are using no-proto object so that we don't need to guard against inherited props via
36652         // hasOwnProperty.
36653         var lastBlockMap = createMap();
36654
36655         //watch props
36656         $scope.$watchCollection(rhs, function ngRepeatAction(collection) {
36657           var index, length,
36658               previousNode = $element[0],     // node that cloned nodes should be inserted after
36659                                               // initialized to the comment node anchor
36660               nextNode,
36661               // Same as lastBlockMap but it has the current state. It will become the
36662               // lastBlockMap on the next iteration.
36663               nextBlockMap = createMap(),
36664               collectionLength,
36665               key, value, // key/value of iteration
36666               trackById,
36667               trackByIdFn,
36668               collectionKeys,
36669               block,       // last object information {scope, element, id}
36670               nextBlockOrder,
36671               elementsToRemove;
36672
36673           if (aliasAs) {
36674             $scope[aliasAs] = collection;
36675           }
36676
36677           if (isArrayLike(collection)) {
36678             collectionKeys = collection;
36679             trackByIdFn = trackByIdExpFn || trackByIdArrayFn;
36680           } else {
36681             trackByIdFn = trackByIdExpFn || trackByIdObjFn;
36682             // if object, extract keys, in enumeration order, unsorted
36683             collectionKeys = [];
36684             for (var itemKey in collection) {
36685               if (hasOwnProperty.call(collection, itemKey) && itemKey.charAt(0) !== '$') {
36686                 collectionKeys.push(itemKey);
36687               }
36688             }
36689           }
36690
36691           collectionLength = collectionKeys.length;
36692           nextBlockOrder = new Array(collectionLength);
36693
36694           // locate existing items
36695           for (index = 0; index < collectionLength; index++) {
36696             key = (collection === collectionKeys) ? index : collectionKeys[index];
36697             value = collection[key];
36698             trackById = trackByIdFn(key, value, index);
36699             if (lastBlockMap[trackById]) {
36700               // found previously seen block
36701               block = lastBlockMap[trackById];
36702               delete lastBlockMap[trackById];
36703               nextBlockMap[trackById] = block;
36704               nextBlockOrder[index] = block;
36705             } else if (nextBlockMap[trackById]) {
36706               // if collision detected. restore lastBlockMap and throw an error
36707               forEach(nextBlockOrder, function(block) {
36708                 if (block && block.scope) lastBlockMap[block.id] = block;
36709               });
36710               throw ngRepeatMinErr('dupes',
36711                   "Duplicates in a repeater are not allowed. Use 'track by' expression to specify unique keys. Repeater: {0}, Duplicate key: {1}, Duplicate value: {2}",
36712                   expression, trackById, value);
36713             } else {
36714               // new never before seen block
36715               nextBlockOrder[index] = {id: trackById, scope: undefined, clone: undefined};
36716               nextBlockMap[trackById] = true;
36717             }
36718           }
36719
36720           // remove leftover items
36721           for (var blockKey in lastBlockMap) {
36722             block = lastBlockMap[blockKey];
36723             elementsToRemove = getBlockNodes(block.clone);
36724             $animate.leave(elementsToRemove);
36725             if (elementsToRemove[0].parentNode) {
36726               // if the element was not removed yet because of pending animation, mark it as deleted
36727               // so that we can ignore it later
36728               for (index = 0, length = elementsToRemove.length; index < length; index++) {
36729                 elementsToRemove[index][NG_REMOVED] = true;
36730               }
36731             }
36732             block.scope.$destroy();
36733           }
36734
36735           // we are not using forEach for perf reasons (trying to avoid #call)
36736           for (index = 0; index < collectionLength; index++) {
36737             key = (collection === collectionKeys) ? index : collectionKeys[index];
36738             value = collection[key];
36739             block = nextBlockOrder[index];
36740
36741             if (block.scope) {
36742               // if we have already seen this object, then we need to reuse the
36743               // associated scope/element
36744
36745               nextNode = previousNode;
36746
36747               // skip nodes that are already pending removal via leave animation
36748               do {
36749                 nextNode = nextNode.nextSibling;
36750               } while (nextNode && nextNode[NG_REMOVED]);
36751
36752               if (getBlockStart(block) != nextNode) {
36753                 // existing item which got moved
36754                 $animate.move(getBlockNodes(block.clone), null, jqLite(previousNode));
36755               }
36756               previousNode = getBlockEnd(block);
36757               updateScope(block.scope, index, valueIdentifier, value, keyIdentifier, key, collectionLength);
36758             } else {
36759               // new item which we don't know about
36760               $transclude(function ngRepeatTransclude(clone, scope) {
36761                 block.scope = scope;
36762                 // http://jsperf.com/clone-vs-createcomment
36763                 var endNode = ngRepeatEndComment.cloneNode(false);
36764                 clone[clone.length++] = endNode;
36765
36766                 // TODO(perf): support naked previousNode in `enter` to avoid creation of jqLite wrapper?
36767                 $animate.enter(clone, null, jqLite(previousNode));
36768                 previousNode = endNode;
36769                 // Note: We only need the first/last node of the cloned nodes.
36770                 // However, we need to keep the reference to the jqlite wrapper as it might be changed later
36771                 // by a directive with templateUrl when its template arrives.
36772                 block.clone = clone;
36773                 nextBlockMap[block.id] = block;
36774                 updateScope(block.scope, index, valueIdentifier, value, keyIdentifier, key, collectionLength);
36775               });
36776             }
36777           }
36778           lastBlockMap = nextBlockMap;
36779         });
36780       };
36781     }
36782   };
36783 }];
36784
36785 var NG_HIDE_CLASS = 'ng-hide';
36786 var NG_HIDE_IN_PROGRESS_CLASS = 'ng-hide-animate';
36787 /**
36788  * @ngdoc directive
36789  * @name ngShow
36790  * @multiElement
36791  *
36792  * @description
36793  * The `ngShow` directive shows or hides the given HTML element based on the expression
36794  * provided to the `ngShow` attribute. The element is shown or hidden by removing or adding
36795  * the `.ng-hide` CSS class onto the element. The `.ng-hide` CSS class is predefined
36796  * in AngularJS and sets the display style to none (using an !important flag).
36797  * For CSP mode please add `angular-csp.css` to your html file (see {@link ng.directive:ngCsp ngCsp}).
36798  *
36799  * ```html
36800  * <!-- when $scope.myValue is truthy (element is visible) -->
36801  * <div ng-show="myValue"></div>
36802  *
36803  * <!-- when $scope.myValue is falsy (element is hidden) -->
36804  * <div ng-show="myValue" class="ng-hide"></div>
36805  * ```
36806  *
36807  * When the `ngShow` expression evaluates to a falsy value then the `.ng-hide` CSS class is added to the class
36808  * attribute on the element causing it to become hidden. When truthy, the `.ng-hide` CSS class is removed
36809  * from the element causing the element not to appear hidden.
36810  *
36811  * ## Why is !important used?
36812  *
36813  * You may be wondering why !important is used for the `.ng-hide` CSS class. This is because the `.ng-hide` selector
36814  * can be easily overridden by heavier selectors. For example, something as simple
36815  * as changing the display style on a HTML list item would make hidden elements appear visible.
36816  * This also becomes a bigger issue when dealing with CSS frameworks.
36817  *
36818  * By using !important, the show and hide behavior will work as expected despite any clash between CSS selector
36819  * specificity (when !important isn't used with any conflicting styles). If a developer chooses to override the
36820  * styling to change how to hide an element then it is just a matter of using !important in their own CSS code.
36821  *
36822  * ### Overriding `.ng-hide`
36823  *
36824  * By default, the `.ng-hide` class will style the element with `display: none!important`. If you wish to change
36825  * the hide behavior with ngShow/ngHide then this can be achieved by restating the styles for the `.ng-hide`
36826  * class CSS. Note that the selector that needs to be used is actually `.ng-hide:not(.ng-hide-animate)` to cope
36827  * with extra animation classes that can be added.
36828  *
36829  * ```css
36830  * .ng-hide:not(.ng-hide-animate) {
36831  *   /&#42; this is just another form of hiding an element &#42;/
36832  *   display: block!important;
36833  *   position: absolute;
36834  *   top: -9999px;
36835  *   left: -9999px;
36836  * }
36837  * ```
36838  *
36839  * By default you don't need to override in CSS anything and the animations will work around the display style.
36840  *
36841  * ## A note about animations with `ngShow`
36842  *
36843  * Animations in ngShow/ngHide work with the show and hide events that are triggered when the directive expression
36844  * is true and false. This system works like the animation system present with ngClass except that
36845  * you must also include the !important flag to override the display property
36846  * so that you can perform an animation when the element is hidden during the time of the animation.
36847  *
36848  * ```css
36849  * //
36850  * //a working example can be found at the bottom of this page
36851  * //
36852  * .my-element.ng-hide-add, .my-element.ng-hide-remove {
36853  *   /&#42; this is required as of 1.3x to properly
36854  *      apply all styling in a show/hide animation &#42;/
36855  *   transition: 0s linear all;
36856  * }
36857  *
36858  * .my-element.ng-hide-add-active,
36859  * .my-element.ng-hide-remove-active {
36860  *   /&#42; the transition is defined in the active class &#42;/
36861  *   transition: 1s linear all;
36862  * }
36863  *
36864  * .my-element.ng-hide-add { ... }
36865  * .my-element.ng-hide-add.ng-hide-add-active { ... }
36866  * .my-element.ng-hide-remove { ... }
36867  * .my-element.ng-hide-remove.ng-hide-remove-active { ... }
36868  * ```
36869  *
36870  * Keep in mind that, as of AngularJS version 1.3.0-beta.11, there is no need to change the display
36871  * property to block during animation states--ngAnimate will handle the style toggling automatically for you.
36872  *
36873  * @animations
36874  * addClass: `.ng-hide` - happens after the `ngShow` expression evaluates to a truthy value and the just before contents are set to visible
36875  * removeClass: `.ng-hide` - happens after the `ngShow` expression evaluates to a non truthy value and just before the contents are set to hidden
36876  *
36877  * @element ANY
36878  * @param {expression} ngShow If the {@link guide/expression expression} is truthy
36879  *     then the element is shown or hidden respectively.
36880  *
36881  * @example
36882   <example module="ngAnimate" deps="angular-animate.js" animations="true">
36883     <file name="index.html">
36884       Click me: <input type="checkbox" ng-model="checked" aria-label="Toggle ngHide"><br/>
36885       <div>
36886         Show:
36887         <div class="check-element animate-show" ng-show="checked">
36888           <span class="glyphicon glyphicon-thumbs-up"></span> I show up when your checkbox is checked.
36889         </div>
36890       </div>
36891       <div>
36892         Hide:
36893         <div class="check-element animate-show" ng-hide="checked">
36894           <span class="glyphicon glyphicon-thumbs-down"></span> I hide when your checkbox is checked.
36895         </div>
36896       </div>
36897     </file>
36898     <file name="glyphicons.css">
36899       @import url(../../components/bootstrap-3.1.1/css/bootstrap.css);
36900     </file>
36901     <file name="animations.css">
36902       .animate-show {
36903         line-height: 20px;
36904         opacity: 1;
36905         padding: 10px;
36906         border: 1px solid black;
36907         background: white;
36908       }
36909
36910       .animate-show.ng-hide-add, .animate-show.ng-hide-remove {
36911         transition: all linear 0.5s;
36912       }
36913
36914       .animate-show.ng-hide {
36915         line-height: 0;
36916         opacity: 0;
36917         padding: 0 10px;
36918       }
36919
36920       .check-element {
36921         padding: 10px;
36922         border: 1px solid black;
36923         background: white;
36924       }
36925     </file>
36926     <file name="protractor.js" type="protractor">
36927       var thumbsUp = element(by.css('span.glyphicon-thumbs-up'));
36928       var thumbsDown = element(by.css('span.glyphicon-thumbs-down'));
36929
36930       it('should check ng-show / ng-hide', function() {
36931         expect(thumbsUp.isDisplayed()).toBeFalsy();
36932         expect(thumbsDown.isDisplayed()).toBeTruthy();
36933
36934         element(by.model('checked')).click();
36935
36936         expect(thumbsUp.isDisplayed()).toBeTruthy();
36937         expect(thumbsDown.isDisplayed()).toBeFalsy();
36938       });
36939     </file>
36940   </example>
36941  */
36942 var ngShowDirective = ['$animate', function($animate) {
36943   return {
36944     restrict: 'A',
36945     multiElement: true,
36946     link: function(scope, element, attr) {
36947       scope.$watch(attr.ngShow, function ngShowWatchAction(value) {
36948         // we're adding a temporary, animation-specific class for ng-hide since this way
36949         // we can control when the element is actually displayed on screen without having
36950         // to have a global/greedy CSS selector that breaks when other animations are run.
36951         // Read: https://github.com/angular/angular.js/issues/9103#issuecomment-58335845
36952         $animate[value ? 'removeClass' : 'addClass'](element, NG_HIDE_CLASS, {
36953           tempClasses: NG_HIDE_IN_PROGRESS_CLASS
36954         });
36955       });
36956     }
36957   };
36958 }];
36959
36960
36961 /**
36962  * @ngdoc directive
36963  * @name ngHide
36964  * @multiElement
36965  *
36966  * @description
36967  * The `ngHide` directive shows or hides the given HTML element based on the expression
36968  * provided to the `ngHide` attribute. The element is shown or hidden by removing or adding
36969  * the `ng-hide` CSS class onto the element. The `.ng-hide` CSS class is predefined
36970  * in AngularJS and sets the display style to none (using an !important flag).
36971  * For CSP mode please add `angular-csp.css` to your html file (see {@link ng.directive:ngCsp ngCsp}).
36972  *
36973  * ```html
36974  * <!-- when $scope.myValue is truthy (element is hidden) -->
36975  * <div ng-hide="myValue" class="ng-hide"></div>
36976  *
36977  * <!-- when $scope.myValue is falsy (element is visible) -->
36978  * <div ng-hide="myValue"></div>
36979  * ```
36980  *
36981  * When the `ngHide` expression evaluates to a truthy value then the `.ng-hide` CSS class is added to the class
36982  * attribute on the element causing it to become hidden. When falsy, the `.ng-hide` CSS class is removed
36983  * from the element causing the element not to appear hidden.
36984  *
36985  * ## Why is !important used?
36986  *
36987  * You may be wondering why !important is used for the `.ng-hide` CSS class. This is because the `.ng-hide` selector
36988  * can be easily overridden by heavier selectors. For example, something as simple
36989  * as changing the display style on a HTML list item would make hidden elements appear visible.
36990  * This also becomes a bigger issue when dealing with CSS frameworks.
36991  *
36992  * By using !important, the show and hide behavior will work as expected despite any clash between CSS selector
36993  * specificity (when !important isn't used with any conflicting styles). If a developer chooses to override the
36994  * styling to change how to hide an element then it is just a matter of using !important in their own CSS code.
36995  *
36996  * ### Overriding `.ng-hide`
36997  *
36998  * By default, the `.ng-hide` class will style the element with `display: none!important`. If you wish to change
36999  * the hide behavior with ngShow/ngHide then this can be achieved by restating the styles for the `.ng-hide`
37000  * class in CSS:
37001  *
37002  * ```css
37003  * .ng-hide {
37004  *   /&#42; this is just another form of hiding an element &#42;/
37005  *   display: block!important;
37006  *   position: absolute;
37007  *   top: -9999px;
37008  *   left: -9999px;
37009  * }
37010  * ```
37011  *
37012  * By default you don't need to override in CSS anything and the animations will work around the display style.
37013  *
37014  * ## A note about animations with `ngHide`
37015  *
37016  * Animations in ngShow/ngHide work with the show and hide events that are triggered when the directive expression
37017  * is true and false. This system works like the animation system present with ngClass, except that the `.ng-hide`
37018  * CSS class is added and removed for you instead of your own CSS class.
37019  *
37020  * ```css
37021  * //
37022  * //a working example can be found at the bottom of this page
37023  * //
37024  * .my-element.ng-hide-add, .my-element.ng-hide-remove {
37025  *   transition: 0.5s linear all;
37026  * }
37027  *
37028  * .my-element.ng-hide-add { ... }
37029  * .my-element.ng-hide-add.ng-hide-add-active { ... }
37030  * .my-element.ng-hide-remove { ... }
37031  * .my-element.ng-hide-remove.ng-hide-remove-active { ... }
37032  * ```
37033  *
37034  * Keep in mind that, as of AngularJS version 1.3.0-beta.11, there is no need to change the display
37035  * property to block during animation states--ngAnimate will handle the style toggling automatically for you.
37036  *
37037  * @animations
37038  * removeClass: `.ng-hide` - happens after the `ngHide` expression evaluates to a truthy value and just before the contents are set to hidden
37039  * addClass: `.ng-hide` - happens after the `ngHide` expression evaluates to a non truthy value and just before the contents are set to visible
37040  *
37041  * @element ANY
37042  * @param {expression} ngHide If the {@link guide/expression expression} is truthy then
37043  *     the element is shown or hidden respectively.
37044  *
37045  * @example
37046   <example module="ngAnimate" deps="angular-animate.js" animations="true">
37047     <file name="index.html">
37048       Click me: <input type="checkbox" ng-model="checked" aria-label="Toggle ngShow"><br/>
37049       <div>
37050         Show:
37051         <div class="check-element animate-hide" ng-show="checked">
37052           <span class="glyphicon glyphicon-thumbs-up"></span> I show up when your checkbox is checked.
37053         </div>
37054       </div>
37055       <div>
37056         Hide:
37057         <div class="check-element animate-hide" ng-hide="checked">
37058           <span class="glyphicon glyphicon-thumbs-down"></span> I hide when your checkbox is checked.
37059         </div>
37060       </div>
37061     </file>
37062     <file name="glyphicons.css">
37063       @import url(../../components/bootstrap-3.1.1/css/bootstrap.css);
37064     </file>
37065     <file name="animations.css">
37066       .animate-hide {
37067         transition: all linear 0.5s;
37068         line-height: 20px;
37069         opacity: 1;
37070         padding: 10px;
37071         border: 1px solid black;
37072         background: white;
37073       }
37074
37075       .animate-hide.ng-hide {
37076         line-height: 0;
37077         opacity: 0;
37078         padding: 0 10px;
37079       }
37080
37081       .check-element {
37082         padding: 10px;
37083         border: 1px solid black;
37084         background: white;
37085       }
37086     </file>
37087     <file name="protractor.js" type="protractor">
37088       var thumbsUp = element(by.css('span.glyphicon-thumbs-up'));
37089       var thumbsDown = element(by.css('span.glyphicon-thumbs-down'));
37090
37091       it('should check ng-show / ng-hide', function() {
37092         expect(thumbsUp.isDisplayed()).toBeFalsy();
37093         expect(thumbsDown.isDisplayed()).toBeTruthy();
37094
37095         element(by.model('checked')).click();
37096
37097         expect(thumbsUp.isDisplayed()).toBeTruthy();
37098         expect(thumbsDown.isDisplayed()).toBeFalsy();
37099       });
37100     </file>
37101   </example>
37102  */
37103 var ngHideDirective = ['$animate', function($animate) {
37104   return {
37105     restrict: 'A',
37106     multiElement: true,
37107     link: function(scope, element, attr) {
37108       scope.$watch(attr.ngHide, function ngHideWatchAction(value) {
37109         // The comment inside of the ngShowDirective explains why we add and
37110         // remove a temporary class for the show/hide animation
37111         $animate[value ? 'addClass' : 'removeClass'](element,NG_HIDE_CLASS, {
37112           tempClasses: NG_HIDE_IN_PROGRESS_CLASS
37113         });
37114       });
37115     }
37116   };
37117 }];
37118
37119 /**
37120  * @ngdoc directive
37121  * @name ngStyle
37122  * @restrict AC
37123  *
37124  * @description
37125  * The `ngStyle` directive allows you to set CSS style on an HTML element conditionally.
37126  *
37127  * @element ANY
37128  * @param {expression} ngStyle
37129  *
37130  * {@link guide/expression Expression} which evals to an
37131  * object whose keys are CSS style names and values are corresponding values for those CSS
37132  * keys.
37133  *
37134  * Since some CSS style names are not valid keys for an object, they must be quoted.
37135  * See the 'background-color' style in the example below.
37136  *
37137  * @example
37138    <example>
37139      <file name="index.html">
37140         <input type="button" value="set color" ng-click="myStyle={color:'red'}">
37141         <input type="button" value="set background" ng-click="myStyle={'background-color':'blue'}">
37142         <input type="button" value="clear" ng-click="myStyle={}">
37143         <br/>
37144         <span ng-style="myStyle">Sample Text</span>
37145         <pre>myStyle={{myStyle}}</pre>
37146      </file>
37147      <file name="style.css">
37148        span {
37149          color: black;
37150        }
37151      </file>
37152      <file name="protractor.js" type="protractor">
37153        var colorSpan = element(by.css('span'));
37154
37155        it('should check ng-style', function() {
37156          expect(colorSpan.getCssValue('color')).toBe('rgba(0, 0, 0, 1)');
37157          element(by.css('input[value=\'set color\']')).click();
37158          expect(colorSpan.getCssValue('color')).toBe('rgba(255, 0, 0, 1)');
37159          element(by.css('input[value=clear]')).click();
37160          expect(colorSpan.getCssValue('color')).toBe('rgba(0, 0, 0, 1)');
37161        });
37162      </file>
37163    </example>
37164  */
37165 var ngStyleDirective = ngDirective(function(scope, element, attr) {
37166   scope.$watch(attr.ngStyle, function ngStyleWatchAction(newStyles, oldStyles) {
37167     if (oldStyles && (newStyles !== oldStyles)) {
37168       forEach(oldStyles, function(val, style) { element.css(style, '');});
37169     }
37170     if (newStyles) element.css(newStyles);
37171   }, true);
37172 });
37173
37174 /**
37175  * @ngdoc directive
37176  * @name ngSwitch
37177  * @restrict EA
37178  *
37179  * @description
37180  * The `ngSwitch` directive is used to conditionally swap DOM structure on your template based on a scope expression.
37181  * Elements within `ngSwitch` but without `ngSwitchWhen` or `ngSwitchDefault` directives will be preserved at the location
37182  * as specified in the template.
37183  *
37184  * The directive itself works similar to ngInclude, however, instead of downloading template code (or loading it
37185  * from the template cache), `ngSwitch` simply chooses one of the nested elements and makes it visible based on which element
37186  * matches the value obtained from the evaluated expression. In other words, you define a container element
37187  * (where you place the directive), place an expression on the **`on="..."` attribute**
37188  * (or the **`ng-switch="..."` attribute**), define any inner elements inside of the directive and place
37189  * a when attribute per element. The when attribute is used to inform ngSwitch which element to display when the on
37190  * expression is evaluated. If a matching expression is not found via a when attribute then an element with the default
37191  * attribute is displayed.
37192  *
37193  * <div class="alert alert-info">
37194  * Be aware that the attribute values to match against cannot be expressions. They are interpreted
37195  * as literal string values to match against.
37196  * For example, **`ng-switch-when="someVal"`** will match against the string `"someVal"` not against the
37197  * value of the expression `$scope.someVal`.
37198  * </div>
37199
37200  * @animations
37201  * enter - happens after the ngSwitch contents change and the matched child element is placed inside the container
37202  * leave - happens just after the ngSwitch contents change and just before the former contents are removed from the DOM
37203  *
37204  * @usage
37205  *
37206  * ```
37207  * <ANY ng-switch="expression">
37208  *   <ANY ng-switch-when="matchValue1">...</ANY>
37209  *   <ANY ng-switch-when="matchValue2">...</ANY>
37210  *   <ANY ng-switch-default>...</ANY>
37211  * </ANY>
37212  * ```
37213  *
37214  *
37215  * @scope
37216  * @priority 1200
37217  * @param {*} ngSwitch|on expression to match against <code>ng-switch-when</code>.
37218  * On child elements add:
37219  *
37220  * * `ngSwitchWhen`: the case statement to match against. If match then this
37221  *   case will be displayed. If the same match appears multiple times, all the
37222  *   elements will be displayed.
37223  * * `ngSwitchDefault`: the default case when no other case match. If there
37224  *   are multiple default cases, all of them will be displayed when no other
37225  *   case match.
37226  *
37227  *
37228  * @example
37229   <example module="switchExample" deps="angular-animate.js" animations="true">
37230     <file name="index.html">
37231       <div ng-controller="ExampleController">
37232         <select ng-model="selection" ng-options="item for item in items">
37233         </select>
37234         <code>selection={{selection}}</code>
37235         <hr/>
37236         <div class="animate-switch-container"
37237           ng-switch on="selection">
37238             <div class="animate-switch" ng-switch-when="settings">Settings Div</div>
37239             <div class="animate-switch" ng-switch-when="home">Home Span</div>
37240             <div class="animate-switch" ng-switch-default>default</div>
37241         </div>
37242       </div>
37243     </file>
37244     <file name="script.js">
37245       angular.module('switchExample', ['ngAnimate'])
37246         .controller('ExampleController', ['$scope', function($scope) {
37247           $scope.items = ['settings', 'home', 'other'];
37248           $scope.selection = $scope.items[0];
37249         }]);
37250     </file>
37251     <file name="animations.css">
37252       .animate-switch-container {
37253         position:relative;
37254         background:white;
37255         border:1px solid black;
37256         height:40px;
37257         overflow:hidden;
37258       }
37259
37260       .animate-switch {
37261         padding:10px;
37262       }
37263
37264       .animate-switch.ng-animate {
37265         transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
37266
37267         position:absolute;
37268         top:0;
37269         left:0;
37270         right:0;
37271         bottom:0;
37272       }
37273
37274       .animate-switch.ng-leave.ng-leave-active,
37275       .animate-switch.ng-enter {
37276         top:-50px;
37277       }
37278       .animate-switch.ng-leave,
37279       .animate-switch.ng-enter.ng-enter-active {
37280         top:0;
37281       }
37282     </file>
37283     <file name="protractor.js" type="protractor">
37284       var switchElem = element(by.css('[ng-switch]'));
37285       var select = element(by.model('selection'));
37286
37287       it('should start in settings', function() {
37288         expect(switchElem.getText()).toMatch(/Settings Div/);
37289       });
37290       it('should change to home', function() {
37291         select.all(by.css('option')).get(1).click();
37292         expect(switchElem.getText()).toMatch(/Home Span/);
37293       });
37294       it('should select default', function() {
37295         select.all(by.css('option')).get(2).click();
37296         expect(switchElem.getText()).toMatch(/default/);
37297       });
37298     </file>
37299   </example>
37300  */
37301 var ngSwitchDirective = ['$animate', function($animate) {
37302   return {
37303     require: 'ngSwitch',
37304
37305     // asks for $scope to fool the BC controller module
37306     controller: ['$scope', function ngSwitchController() {
37307      this.cases = {};
37308     }],
37309     link: function(scope, element, attr, ngSwitchController) {
37310       var watchExpr = attr.ngSwitch || attr.on,
37311           selectedTranscludes = [],
37312           selectedElements = [],
37313           previousLeaveAnimations = [],
37314           selectedScopes = [];
37315
37316       var spliceFactory = function(array, index) {
37317           return function() { array.splice(index, 1); };
37318       };
37319
37320       scope.$watch(watchExpr, function ngSwitchWatchAction(value) {
37321         var i, ii;
37322         for (i = 0, ii = previousLeaveAnimations.length; i < ii; ++i) {
37323           $animate.cancel(previousLeaveAnimations[i]);
37324         }
37325         previousLeaveAnimations.length = 0;
37326
37327         for (i = 0, ii = selectedScopes.length; i < ii; ++i) {
37328           var selected = getBlockNodes(selectedElements[i].clone);
37329           selectedScopes[i].$destroy();
37330           var promise = previousLeaveAnimations[i] = $animate.leave(selected);
37331           promise.then(spliceFactory(previousLeaveAnimations, i));
37332         }
37333
37334         selectedElements.length = 0;
37335         selectedScopes.length = 0;
37336
37337         if ((selectedTranscludes = ngSwitchController.cases['!' + value] || ngSwitchController.cases['?'])) {
37338           forEach(selectedTranscludes, function(selectedTransclude) {
37339             selectedTransclude.transclude(function(caseElement, selectedScope) {
37340               selectedScopes.push(selectedScope);
37341               var anchor = selectedTransclude.element;
37342               caseElement[caseElement.length++] = document.createComment(' end ngSwitchWhen: ');
37343               var block = { clone: caseElement };
37344
37345               selectedElements.push(block);
37346               $animate.enter(caseElement, anchor.parent(), anchor);
37347             });
37348           });
37349         }
37350       });
37351     }
37352   };
37353 }];
37354
37355 var ngSwitchWhenDirective = ngDirective({
37356   transclude: 'element',
37357   priority: 1200,
37358   require: '^ngSwitch',
37359   multiElement: true,
37360   link: function(scope, element, attrs, ctrl, $transclude) {
37361     ctrl.cases['!' + attrs.ngSwitchWhen] = (ctrl.cases['!' + attrs.ngSwitchWhen] || []);
37362     ctrl.cases['!' + attrs.ngSwitchWhen].push({ transclude: $transclude, element: element });
37363   }
37364 });
37365
37366 var ngSwitchDefaultDirective = ngDirective({
37367   transclude: 'element',
37368   priority: 1200,
37369   require: '^ngSwitch',
37370   multiElement: true,
37371   link: function(scope, element, attr, ctrl, $transclude) {
37372     ctrl.cases['?'] = (ctrl.cases['?'] || []);
37373     ctrl.cases['?'].push({ transclude: $transclude, element: element });
37374    }
37375 });
37376
37377 /**
37378  * @ngdoc directive
37379  * @name ngTransclude
37380  * @restrict EAC
37381  *
37382  * @description
37383  * Directive that marks the insertion point for the transcluded DOM of the nearest parent directive that uses transclusion.
37384  *
37385  * Any existing content of the element that this directive is placed on will be removed before the transcluded content is inserted.
37386  *
37387  * @element ANY
37388  *
37389  * @example
37390    <example module="transcludeExample">
37391      <file name="index.html">
37392        <script>
37393          angular.module('transcludeExample', [])
37394           .directive('pane', function(){
37395              return {
37396                restrict: 'E',
37397                transclude: true,
37398                scope: { title:'@' },
37399                template: '<div style="border: 1px solid black;">' +
37400                            '<div style="background-color: gray">{{title}}</div>' +
37401                            '<ng-transclude></ng-transclude>' +
37402                          '</div>'
37403              };
37404          })
37405          .controller('ExampleController', ['$scope', function($scope) {
37406            $scope.title = 'Lorem Ipsum';
37407            $scope.text = 'Neque porro quisquam est qui dolorem ipsum quia dolor...';
37408          }]);
37409        </script>
37410        <div ng-controller="ExampleController">
37411          <input ng-model="title" aria-label="title"> <br/>
37412          <textarea ng-model="text" aria-label="text"></textarea> <br/>
37413          <pane title="{{title}}">{{text}}</pane>
37414        </div>
37415      </file>
37416      <file name="protractor.js" type="protractor">
37417         it('should have transcluded', function() {
37418           var titleElement = element(by.model('title'));
37419           titleElement.clear();
37420           titleElement.sendKeys('TITLE');
37421           var textElement = element(by.model('text'));
37422           textElement.clear();
37423           textElement.sendKeys('TEXT');
37424           expect(element(by.binding('title')).getText()).toEqual('TITLE');
37425           expect(element(by.binding('text')).getText()).toEqual('TEXT');
37426         });
37427      </file>
37428    </example>
37429  *
37430  */
37431 var ngTranscludeDirective = ngDirective({
37432   restrict: 'EAC',
37433   link: function($scope, $element, $attrs, controller, $transclude) {
37434     if (!$transclude) {
37435       throw minErr('ngTransclude')('orphan',
37436        'Illegal use of ngTransclude directive in the template! ' +
37437        'No parent directive that requires a transclusion found. ' +
37438        'Element: {0}',
37439        startingTag($element));
37440     }
37441
37442     $transclude(function(clone) {
37443       $element.empty();
37444       $element.append(clone);
37445     });
37446   }
37447 });
37448
37449 /**
37450  * @ngdoc directive
37451  * @name script
37452  * @restrict E
37453  *
37454  * @description
37455  * Load the content of a `<script>` element into {@link ng.$templateCache `$templateCache`}, so that the
37456  * template can be used by {@link ng.directive:ngInclude `ngInclude`},
37457  * {@link ngRoute.directive:ngView `ngView`}, or {@link guide/directive directives}. The type of the
37458  * `<script>` element must be specified as `text/ng-template`, and a cache name for the template must be
37459  * assigned through the element's `id`, which can then be used as a directive's `templateUrl`.
37460  *
37461  * @param {string} type Must be set to `'text/ng-template'`.
37462  * @param {string} id Cache name of the template.
37463  *
37464  * @example
37465   <example>
37466     <file name="index.html">
37467       <script type="text/ng-template" id="/tpl.html">
37468         Content of the template.
37469       </script>
37470
37471       <a ng-click="currentTpl='/tpl.html'" id="tpl-link">Load inlined template</a>
37472       <div id="tpl-content" ng-include src="currentTpl"></div>
37473     </file>
37474     <file name="protractor.js" type="protractor">
37475       it('should load template defined inside script tag', function() {
37476         element(by.css('#tpl-link')).click();
37477         expect(element(by.css('#tpl-content')).getText()).toMatch(/Content of the template/);
37478       });
37479     </file>
37480   </example>
37481  */
37482 var scriptDirective = ['$templateCache', function($templateCache) {
37483   return {
37484     restrict: 'E',
37485     terminal: true,
37486     compile: function(element, attr) {
37487       if (attr.type == 'text/ng-template') {
37488         var templateUrl = attr.id,
37489             text = element[0].text;
37490
37491         $templateCache.put(templateUrl, text);
37492       }
37493     }
37494   };
37495 }];
37496
37497 var noopNgModelController = { $setViewValue: noop, $render: noop };
37498
37499 function chromeHack(optionElement) {
37500   // Workaround for https://code.google.com/p/chromium/issues/detail?id=381459
37501   // Adding an <option selected="selected"> element to a <select required="required"> should
37502   // automatically select the new element
37503   if (optionElement[0].hasAttribute('selected')) {
37504     optionElement[0].selected = true;
37505   }
37506 }
37507
37508 /**
37509  * @ngdoc type
37510  * @name  select.SelectController
37511  * @description
37512  * The controller for the `<select>` directive. This provides support for reading
37513  * and writing the selected value(s) of the control and also coordinates dynamically
37514  * added `<option>` elements, perhaps by an `ngRepeat` directive.
37515  */
37516 var SelectController =
37517         ['$element', '$scope', '$attrs', function($element, $scope, $attrs) {
37518
37519   var self = this,
37520       optionsMap = new HashMap();
37521
37522   // If the ngModel doesn't get provided then provide a dummy noop version to prevent errors
37523   self.ngModelCtrl = noopNgModelController;
37524
37525   // The "unknown" option is one that is prepended to the list if the viewValue
37526   // does not match any of the options. When it is rendered the value of the unknown
37527   // option is '? XXX ?' where XXX is the hashKey of the value that is not known.
37528   //
37529   // We can't just jqLite('<option>') since jqLite is not smart enough
37530   // to create it in <select> and IE barfs otherwise.
37531   self.unknownOption = jqLite(document.createElement('option'));
37532   self.renderUnknownOption = function(val) {
37533     var unknownVal = '? ' + hashKey(val) + ' ?';
37534     self.unknownOption.val(unknownVal);
37535     $element.prepend(self.unknownOption);
37536     $element.val(unknownVal);
37537   };
37538
37539   $scope.$on('$destroy', function() {
37540     // disable unknown option so that we don't do work when the whole select is being destroyed
37541     self.renderUnknownOption = noop;
37542   });
37543
37544   self.removeUnknownOption = function() {
37545     if (self.unknownOption.parent()) self.unknownOption.remove();
37546   };
37547
37548
37549   // Read the value of the select control, the implementation of this changes depending
37550   // upon whether the select can have multiple values and whether ngOptions is at work.
37551   self.readValue = function readSingleValue() {
37552     self.removeUnknownOption();
37553     return $element.val();
37554   };
37555
37556
37557   // Write the value to the select control, the implementation of this changes depending
37558   // upon whether the select can have multiple values and whether ngOptions is at work.
37559   self.writeValue = function writeSingleValue(value) {
37560     if (self.hasOption(value)) {
37561       self.removeUnknownOption();
37562       $element.val(value);
37563       if (value === '') self.emptyOption.prop('selected', true); // to make IE9 happy
37564     } else {
37565       if (value == null && self.emptyOption) {
37566         self.removeUnknownOption();
37567         $element.val('');
37568       } else {
37569         self.renderUnknownOption(value);
37570       }
37571     }
37572   };
37573
37574
37575   // Tell the select control that an option, with the given value, has been added
37576   self.addOption = function(value, element) {
37577     assertNotHasOwnProperty(value, '"option value"');
37578     if (value === '') {
37579       self.emptyOption = element;
37580     }
37581     var count = optionsMap.get(value) || 0;
37582     optionsMap.put(value, count + 1);
37583     self.ngModelCtrl.$render();
37584     chromeHack(element);
37585   };
37586
37587   // Tell the select control that an option, with the given value, has been removed
37588   self.removeOption = function(value) {
37589     var count = optionsMap.get(value);
37590     if (count) {
37591       if (count === 1) {
37592         optionsMap.remove(value);
37593         if (value === '') {
37594           self.emptyOption = undefined;
37595         }
37596       } else {
37597         optionsMap.put(value, count - 1);
37598       }
37599     }
37600   };
37601
37602   // Check whether the select control has an option matching the given value
37603   self.hasOption = function(value) {
37604     return !!optionsMap.get(value);
37605   };
37606
37607
37608   self.registerOption = function(optionScope, optionElement, optionAttrs, interpolateValueFn, interpolateTextFn) {
37609
37610     if (interpolateValueFn) {
37611       // The value attribute is interpolated
37612       var oldVal;
37613       optionAttrs.$observe('value', function valueAttributeObserveAction(newVal) {
37614         if (isDefined(oldVal)) {
37615           self.removeOption(oldVal);
37616         }
37617         oldVal = newVal;
37618         self.addOption(newVal, optionElement);
37619       });
37620     } else if (interpolateTextFn) {
37621       // The text content is interpolated
37622       optionScope.$watch(interpolateTextFn, function interpolateWatchAction(newVal, oldVal) {
37623         optionAttrs.$set('value', newVal);
37624         if (oldVal !== newVal) {
37625           self.removeOption(oldVal);
37626         }
37627         self.addOption(newVal, optionElement);
37628       });
37629     } else {
37630       // The value attribute is static
37631       self.addOption(optionAttrs.value, optionElement);
37632     }
37633
37634     optionElement.on('$destroy', function() {
37635       self.removeOption(optionAttrs.value);
37636       self.ngModelCtrl.$render();
37637     });
37638   };
37639 }];
37640
37641 /**
37642  * @ngdoc directive
37643  * @name select
37644  * @restrict E
37645  *
37646  * @description
37647  * HTML `SELECT` element with angular data-binding.
37648  *
37649  * The `select` directive is used together with {@link ngModel `ngModel`} to provide data-binding
37650  * between the scope and the `<select>` control (including setting default values).
37651  * Ìt also handles dynamic `<option>` elements, which can be added using the {@link ngRepeat `ngRepeat}` or
37652  * {@link ngOptions `ngOptions`} directives.
37653  *
37654  * When an item in the `<select>` menu is selected, the value of the selected option will be bound
37655  * to the model identified by the `ngModel` directive. With static or repeated options, this is
37656  * the content of the `value` attribute or the textContent of the `<option>`, if the value attribute is missing.
37657  * If you want dynamic value attributes, you can use interpolation inside the value attribute.
37658  *
37659  * <div class="alert alert-warning">
37660  * Note that the value of a `select` directive used without `ngOptions` is always a string.
37661  * When the model needs to be bound to a non-string value, you must either explictly convert it
37662  * using a directive (see example below) or use `ngOptions` to specify the set of options.
37663  * This is because an option element can only be bound to string values at present.
37664  * </div>
37665  *
37666  * If the viewValue of `ngModel` does not match any of the options, then the control
37667  * will automatically add an "unknown" option, which it then removes when the mismatch is resolved.
37668  *
37669  * Optionally, a single hard-coded `<option>` element, with the value set to an empty string, can
37670  * be nested into the `<select>` element. This element will then represent the `null` or "not selected"
37671  * option. See example below for demonstration.
37672  *
37673  * <div class="alert alert-info">
37674  * In many cases, `ngRepeat` can be used on `<option>` elements instead of {@link ng.directive:ngOptions
37675  * ngOptions} to achieve a similar result. However, `ngOptions` provides some benefits, such as
37676  * more flexibility in how the `<select>`'s model is assigned via the `select` **`as`** part of the
37677  * comprehension expression, and additionally in reducing memory and increasing speed by not creating
37678  * a new scope for each repeated instance.
37679  * </div>
37680  *
37681  *
37682  * @param {string} ngModel Assignable angular expression to data-bind to.
37683  * @param {string=} name Property name of the form under which the control is published.
37684  * @param {string=} multiple Allows multiple options to be selected. The selected values will be
37685  *     bound to the model as an array.
37686  * @param {string=} required Sets `required` validation error key if the value is not entered.
37687  * @param {string=} ngRequired Adds required attribute and required validation constraint to
37688  * the element when the ngRequired expression evaluates to true. Use ngRequired instead of required
37689  * when you want to data-bind to the required attribute.
37690  * @param {string=} ngChange Angular expression to be executed when selected option(s) changes due to user
37691  *    interaction with the select element.
37692  * @param {string=} ngOptions sets the options that the select is populated with and defines what is
37693  * set on the model on selection. See {@link ngOptions `ngOptions`}.
37694  *
37695  * @example
37696  * ### Simple `select` elements with static options
37697  *
37698  * <example name="static-select" module="staticSelect">
37699  * <file name="index.html">
37700  * <div ng-controller="ExampleController">
37701  *   <form name="myForm">
37702  *     <label for="singleSelect"> Single select: </label><br>
37703  *     <select name="singleSelect" ng-model="data.singleSelect">
37704  *       <option value="option-1">Option 1</option>
37705  *       <option value="option-2">Option 2</option>
37706  *     </select><br>
37707  *
37708  *     <label for="singleSelect"> Single select with "not selected" option and dynamic option values: </label><br>
37709  *     <select name="singleSelect" id="singleSelect" ng-model="data.singleSelect">
37710  *       <option value="">---Please select---</option> <!-- not selected / blank option -->
37711  *       <option value="{{data.option1}}">Option 1</option> <!-- interpolation -->
37712  *       <option value="option-2">Option 2</option>
37713  *     </select><br>
37714  *     <button ng-click="forceUnknownOption()">Force unknown option</button><br>
37715  *     <tt>singleSelect = {{data.singleSelect}}</tt>
37716  *
37717  *     <hr>
37718  *     <label for="multipleSelect"> Multiple select: </label><br>
37719  *     <select name="multipleSelect" id="multipleSelect" ng-model="data.multipleSelect" multiple>
37720  *       <option value="option-1">Option 1</option>
37721  *       <option value="option-2">Option 2</option>
37722  *       <option value="option-3">Option 3</option>
37723  *     </select><br>
37724  *     <tt>multipleSelect = {{data.multipleSelect}}</tt><br/>
37725  *   </form>
37726  * </div>
37727  * </file>
37728  * <file name="app.js">
37729  *  angular.module('staticSelect', [])
37730  *    .controller('ExampleController', ['$scope', function($scope) {
37731  *      $scope.data = {
37732  *       singleSelect: null,
37733  *       multipleSelect: [],
37734  *       option1: 'option-1',
37735  *      };
37736  *
37737  *      $scope.forceUnknownOption = function() {
37738  *        $scope.data.singleSelect = 'nonsense';
37739  *      };
37740  *   }]);
37741  * </file>
37742  *</example>
37743  *
37744  * ### Using `ngRepeat` to generate `select` options
37745  * <example name="ngrepeat-select" module="ngrepeatSelect">
37746  * <file name="index.html">
37747  * <div ng-controller="ExampleController">
37748  *   <form name="myForm">
37749  *     <label for="repeatSelect"> Repeat select: </label>
37750  *     <select name="repeatSelect" id="repeatSelect" ng-model="data.repeatSelect">
37751  *       <option ng-repeat="option in data.availableOptions" value="{{option.id}}">{{option.name}}</option>
37752  *     </select>
37753  *   </form>
37754  *   <hr>
37755  *   <tt>repeatSelect = {{data.repeatSelect}}</tt><br/>
37756  * </div>
37757  * </file>
37758  * <file name="app.js">
37759  *  angular.module('ngrepeatSelect', [])
37760  *    .controller('ExampleController', ['$scope', function($scope) {
37761  *      $scope.data = {
37762  *       repeatSelect: null,
37763  *       availableOptions: [
37764  *         {id: '1', name: 'Option A'},
37765  *         {id: '2', name: 'Option B'},
37766  *         {id: '3', name: 'Option C'}
37767  *       ],
37768  *      };
37769  *   }]);
37770  * </file>
37771  *</example>
37772  *
37773  *
37774  * ### Using `select` with `ngOptions` and setting a default value
37775  * See the {@link ngOptions ngOptions documentation} for more `ngOptions` usage examples.
37776  *
37777  * <example name="select-with-default-values" module="defaultValueSelect">
37778  * <file name="index.html">
37779  * <div ng-controller="ExampleController">
37780  *   <form name="myForm">
37781  *     <label for="mySelect">Make a choice:</label>
37782  *     <select name="mySelect" id="mySelect"
37783  *       ng-options="option.name for option in data.availableOptions track by option.id"
37784  *       ng-model="data.selectedOption"></select>
37785  *   </form>
37786  *   <hr>
37787  *   <tt>option = {{data.selectedOption}}</tt><br/>
37788  * </div>
37789  * </file>
37790  * <file name="app.js">
37791  *  angular.module('defaultValueSelect', [])
37792  *    .controller('ExampleController', ['$scope', function($scope) {
37793  *      $scope.data = {
37794  *       availableOptions: [
37795  *         {id: '1', name: 'Option A'},
37796  *         {id: '2', name: 'Option B'},
37797  *         {id: '3', name: 'Option C'}
37798  *       ],
37799  *       selectedOption: {id: '3', name: 'Option C'} //This sets the default value of the select in the ui
37800  *       };
37801  *   }]);
37802  * </file>
37803  *</example>
37804  *
37805  *
37806  * ### Binding `select` to a non-string value via `ngModel` parsing / formatting
37807  *
37808  * <example name="select-with-non-string-options" module="nonStringSelect">
37809  *   <file name="index.html">
37810  *     <select ng-model="model.id" convert-to-number>
37811  *       <option value="0">Zero</option>
37812  *       <option value="1">One</option>
37813  *       <option value="2">Two</option>
37814  *     </select>
37815  *     {{ model }}
37816  *   </file>
37817  *   <file name="app.js">
37818  *     angular.module('nonStringSelect', [])
37819  *       .run(function($rootScope) {
37820  *         $rootScope.model = { id: 2 };
37821  *       })
37822  *       .directive('convertToNumber', function() {
37823  *         return {
37824  *           require: 'ngModel',
37825  *           link: function(scope, element, attrs, ngModel) {
37826  *             ngModel.$parsers.push(function(val) {
37827  *               return parseInt(val, 10);
37828  *             });
37829  *             ngModel.$formatters.push(function(val) {
37830  *               return '' + val;
37831  *             });
37832  *           }
37833  *         };
37834  *       });
37835  *   </file>
37836  *   <file name="protractor.js" type="protractor">
37837  *     it('should initialize to model', function() {
37838  *       var select = element(by.css('select'));
37839  *       expect(element(by.model('model.id')).$('option:checked').getText()).toEqual('Two');
37840  *     });
37841  *   </file>
37842  * </example>
37843  *
37844  */
37845 var selectDirective = function() {
37846
37847   return {
37848     restrict: 'E',
37849     require: ['select', '?ngModel'],
37850     controller: SelectController,
37851     priority: 1,
37852     link: {
37853       pre: selectPreLink
37854     }
37855   };
37856
37857   function selectPreLink(scope, element, attr, ctrls) {
37858
37859       // if ngModel is not defined, we don't need to do anything
37860       var ngModelCtrl = ctrls[1];
37861       if (!ngModelCtrl) return;
37862
37863       var selectCtrl = ctrls[0];
37864
37865       selectCtrl.ngModelCtrl = ngModelCtrl;
37866
37867       // We delegate rendering to the `writeValue` method, which can be changed
37868       // if the select can have multiple selected values or if the options are being
37869       // generated by `ngOptions`
37870       ngModelCtrl.$render = function() {
37871         selectCtrl.writeValue(ngModelCtrl.$viewValue);
37872       };
37873
37874       // When the selected item(s) changes we delegate getting the value of the select control
37875       // to the `readValue` method, which can be changed if the select can have multiple
37876       // selected values or if the options are being generated by `ngOptions`
37877       element.on('change', function() {
37878         scope.$apply(function() {
37879           ngModelCtrl.$setViewValue(selectCtrl.readValue());
37880         });
37881       });
37882
37883       // If the select allows multiple values then we need to modify how we read and write
37884       // values from and to the control; also what it means for the value to be empty and
37885       // we have to add an extra watch since ngModel doesn't work well with arrays - it
37886       // doesn't trigger rendering if only an item in the array changes.
37887       if (attr.multiple) {
37888
37889         // Read value now needs to check each option to see if it is selected
37890         selectCtrl.readValue = function readMultipleValue() {
37891           var array = [];
37892           forEach(element.find('option'), function(option) {
37893             if (option.selected) {
37894               array.push(option.value);
37895             }
37896           });
37897           return array;
37898         };
37899
37900         // Write value now needs to set the selected property of each matching option
37901         selectCtrl.writeValue = function writeMultipleValue(value) {
37902           var items = new HashMap(value);
37903           forEach(element.find('option'), function(option) {
37904             option.selected = isDefined(items.get(option.value));
37905           });
37906         };
37907
37908         // we have to do it on each watch since ngModel watches reference, but
37909         // we need to work of an array, so we need to see if anything was inserted/removed
37910         var lastView, lastViewRef = NaN;
37911         scope.$watch(function selectMultipleWatch() {
37912           if (lastViewRef === ngModelCtrl.$viewValue && !equals(lastView, ngModelCtrl.$viewValue)) {
37913             lastView = shallowCopy(ngModelCtrl.$viewValue);
37914             ngModelCtrl.$render();
37915           }
37916           lastViewRef = ngModelCtrl.$viewValue;
37917         });
37918
37919         // If we are a multiple select then value is now a collection
37920         // so the meaning of $isEmpty changes
37921         ngModelCtrl.$isEmpty = function(value) {
37922           return !value || value.length === 0;
37923         };
37924
37925       }
37926     }
37927 };
37928
37929
37930 // The option directive is purely designed to communicate the existence (or lack of)
37931 // of dynamically created (and destroyed) option elements to their containing select
37932 // directive via its controller.
37933 var optionDirective = ['$interpolate', function($interpolate) {
37934   return {
37935     restrict: 'E',
37936     priority: 100,
37937     compile: function(element, attr) {
37938
37939       if (isDefined(attr.value)) {
37940         // If the value attribute is defined, check if it contains an interpolation
37941         var interpolateValueFn = $interpolate(attr.value, true);
37942       } else {
37943         // If the value attribute is not defined then we fall back to the
37944         // text content of the option element, which may be interpolated
37945         var interpolateTextFn = $interpolate(element.text(), true);
37946         if (!interpolateTextFn) {
37947           attr.$set('value', element.text());
37948         }
37949       }
37950
37951       return function(scope, element, attr) {
37952
37953         // This is an optimization over using ^^ since we don't want to have to search
37954         // all the way to the root of the DOM for every single option element
37955         var selectCtrlName = '$selectController',
37956             parent = element.parent(),
37957             selectCtrl = parent.data(selectCtrlName) ||
37958               parent.parent().data(selectCtrlName); // in case we are in optgroup
37959
37960         if (selectCtrl) {
37961           selectCtrl.registerOption(scope, element, attr, interpolateValueFn, interpolateTextFn);
37962         }
37963       };
37964     }
37965   };
37966 }];
37967
37968 var styleDirective = valueFn({
37969   restrict: 'E',
37970   terminal: false
37971 });
37972
37973 var requiredDirective = function() {
37974   return {
37975     restrict: 'A',
37976     require: '?ngModel',
37977     link: function(scope, elm, attr, ctrl) {
37978       if (!ctrl) return;
37979       attr.required = true; // force truthy in case we are on non input element
37980
37981       ctrl.$validators.required = function(modelValue, viewValue) {
37982         return !attr.required || !ctrl.$isEmpty(viewValue);
37983       };
37984
37985       attr.$observe('required', function() {
37986         ctrl.$validate();
37987       });
37988     }
37989   };
37990 };
37991
37992
37993 var patternDirective = function() {
37994   return {
37995     restrict: 'A',
37996     require: '?ngModel',
37997     link: function(scope, elm, attr, ctrl) {
37998       if (!ctrl) return;
37999
38000       var regexp, patternExp = attr.ngPattern || attr.pattern;
38001       attr.$observe('pattern', function(regex) {
38002         if (isString(regex) && regex.length > 0) {
38003           regex = new RegExp('^' + regex + '$');
38004         }
38005
38006         if (regex && !regex.test) {
38007           throw minErr('ngPattern')('noregexp',
38008             'Expected {0} to be a RegExp but was {1}. Element: {2}', patternExp,
38009             regex, startingTag(elm));
38010         }
38011
38012         regexp = regex || undefined;
38013         ctrl.$validate();
38014       });
38015
38016       ctrl.$validators.pattern = function(modelValue, viewValue) {
38017         // HTML5 pattern constraint validates the input value, so we validate the viewValue
38018         return ctrl.$isEmpty(viewValue) || isUndefined(regexp) || regexp.test(viewValue);
38019       };
38020     }
38021   };
38022 };
38023
38024
38025 var maxlengthDirective = function() {
38026   return {
38027     restrict: 'A',
38028     require: '?ngModel',
38029     link: function(scope, elm, attr, ctrl) {
38030       if (!ctrl) return;
38031
38032       var maxlength = -1;
38033       attr.$observe('maxlength', function(value) {
38034         var intVal = toInt(value);
38035         maxlength = isNaN(intVal) ? -1 : intVal;
38036         ctrl.$validate();
38037       });
38038       ctrl.$validators.maxlength = function(modelValue, viewValue) {
38039         return (maxlength < 0) || ctrl.$isEmpty(viewValue) || (viewValue.length <= maxlength);
38040       };
38041     }
38042   };
38043 };
38044
38045 var minlengthDirective = function() {
38046   return {
38047     restrict: 'A',
38048     require: '?ngModel',
38049     link: function(scope, elm, attr, ctrl) {
38050       if (!ctrl) return;
38051
38052       var minlength = 0;
38053       attr.$observe('minlength', function(value) {
38054         minlength = toInt(value) || 0;
38055         ctrl.$validate();
38056       });
38057       ctrl.$validators.minlength = function(modelValue, viewValue) {
38058         return ctrl.$isEmpty(viewValue) || viewValue.length >= minlength;
38059       };
38060     }
38061   };
38062 };
38063
38064 if (window.angular.bootstrap) {
38065   //AngularJS is already loaded, so we can return here...
38066   console.log('WARNING: Tried to load angular more than once.');
38067   return;
38068 }
38069
38070 //try to bind to jquery now so that one can write jqLite(document).ready()
38071 //but we will rebind on bootstrap again.
38072 bindJQuery();
38073
38074 publishExternalAPI(angular);
38075
38076 angular.module("ngLocale", [], ["$provide", function($provide) {
38077 var PLURAL_CATEGORY = {ZERO: "zero", ONE: "one", TWO: "two", FEW: "few", MANY: "many", OTHER: "other"};
38078 function getDecimals(n) {
38079   n = n + '';
38080   var i = n.indexOf('.');
38081   return (i == -1) ? 0 : n.length - i - 1;
38082 }
38083
38084 function getVF(n, opt_precision) {
38085   var v = opt_precision;
38086
38087   if (undefined === v) {
38088     v = Math.min(getDecimals(n), 3);
38089   }
38090
38091   var base = Math.pow(10, v);
38092   var f = ((n * base) | 0) % base;
38093   return {v: v, f: f};
38094 }
38095
38096 $provide.value("$locale", {
38097   "DATETIME_FORMATS": {
38098     "AMPMS": [
38099       "AM",
38100       "PM"
38101     ],
38102     "DAY": [
38103       "Sunday",
38104       "Monday",
38105       "Tuesday",
38106       "Wednesday",
38107       "Thursday",
38108       "Friday",
38109       "Saturday"
38110     ],
38111     "ERANAMES": [
38112       "Before Christ",
38113       "Anno Domini"
38114     ],
38115     "ERAS": [
38116       "BC",
38117       "AD"
38118     ],
38119     "FIRSTDAYOFWEEK": 6,
38120     "MONTH": [
38121       "January",
38122       "February",
38123       "March",
38124       "April",
38125       "May",
38126       "June",
38127       "July",
38128       "August",
38129       "September",
38130       "October",
38131       "November",
38132       "December"
38133     ],
38134     "SHORTDAY": [
38135       "Sun",
38136       "Mon",
38137       "Tue",
38138       "Wed",
38139       "Thu",
38140       "Fri",
38141       "Sat"
38142     ],
38143     "SHORTMONTH": [
38144       "Jan",
38145       "Feb",
38146       "Mar",
38147       "Apr",
38148       "May",
38149       "Jun",
38150       "Jul",
38151       "Aug",
38152       "Sep",
38153       "Oct",
38154       "Nov",
38155       "Dec"
38156     ],
38157     "WEEKENDRANGE": [
38158       5,
38159       6
38160     ],
38161     "fullDate": "EEEE, MMMM d, y",
38162     "longDate": "MMMM d, y",
38163     "medium": "MMM d, y h:mm:ss a",
38164     "mediumDate": "MMM d, y",
38165     "mediumTime": "h:mm:ss a",
38166     "short": "M/d/yy h:mm a",
38167     "shortDate": "M/d/yy",
38168     "shortTime": "h:mm a"
38169   },
38170   "NUMBER_FORMATS": {
38171     "CURRENCY_SYM": "$",
38172     "DECIMAL_SEP": ".",
38173     "GROUP_SEP": ",",
38174     "PATTERNS": [
38175       {
38176         "gSize": 3,
38177         "lgSize": 3,
38178         "maxFrac": 3,
38179         "minFrac": 0,
38180         "minInt": 1,
38181         "negPre": "-",
38182         "negSuf": "",
38183         "posPre": "",
38184         "posSuf": ""
38185       },
38186       {
38187         "gSize": 3,
38188         "lgSize": 3,
38189         "maxFrac": 2,
38190         "minFrac": 2,
38191         "minInt": 1,
38192         "negPre": "-\u00a4",
38193         "negSuf": "",
38194         "posPre": "\u00a4",
38195         "posSuf": ""
38196       }
38197     ]
38198   },
38199   "id": "en-us",
38200   "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;}
38201 });
38202 }]);
38203
38204 /**
38205  * Setup file for the Scenario.
38206  * Must be first in the compilation/bootstrap list.
38207  */
38208
38209 // Public namespace
38210 angular.scenario = angular.scenario || {};
38211
38212 /**
38213  * Expose jQuery (e.g. for custom dsl extensions).
38214  */
38215 angular.scenario.jQuery = _jQuery;
38216
38217 /**
38218  * Defines a new output format.
38219  *
38220  * @param {string} name the name of the new output format
38221  * @param {function()} fn function(context, runner) that generates the output
38222  */
38223 angular.scenario.output = angular.scenario.output || function(name, fn) {
38224   angular.scenario.output[name] = fn;
38225 };
38226
38227 /**
38228  * Defines a new DSL statement. If your factory function returns a Future
38229  * it's returned, otherwise the result is assumed to be a map of functions
38230  * for chaining. Chained functions are subject to the same rules.
38231  *
38232  * Note: All functions on the chain are bound to the chain scope so values
38233  *   set on "this" in your statement function are available in the chained
38234  *   functions.
38235  *
38236  * @param {string} name The name of the statement
38237  * @param {function()} fn Factory function(), return a function for
38238  *  the statement.
38239  */
38240 angular.scenario.dsl = angular.scenario.dsl || function(name, fn) {
38241   angular.scenario.dsl[name] = function() {
38242     /* jshint -W040 *//* The dsl binds `this` for us when calling chained functions */
38243     function executeStatement(statement, args) {
38244       var result = statement.apply(this, args);
38245       if (angular.isFunction(result) || result instanceof angular.scenario.Future) {
38246         return result;
38247       }
38248       var self = this;
38249       var chain = angular.extend({}, result);
38250       angular.forEach(chain, function(value, name) {
38251         if (angular.isFunction(value)) {
38252           chain[name] = function() {
38253             return executeStatement.call(self, value, arguments);
38254           };
38255         } else {
38256           chain[name] = value;
38257         }
38258       });
38259       return chain;
38260     }
38261     var statement = fn.apply(this, arguments);
38262     return function() {
38263       return executeStatement.call(this, statement, arguments);
38264     };
38265   };
38266 };
38267
38268 /**
38269  * Defines a new matcher for use with the expects() statement. The value
38270  * this.actual (like in Jasmine) is available in your matcher to compare
38271  * against. Your function should return a boolean. The future is automatically
38272  * created for you.
38273  *
38274  * @param {string} name The name of the matcher
38275  * @param {function()} fn The matching function(expected).
38276  */
38277 angular.scenario.matcher = angular.scenario.matcher || function(name, fn) {
38278   angular.scenario.matcher[name] = function(expected) {
38279     var description = this.future.name +
38280                       (this.inverse ? ' not ' : ' ') + name +
38281                       ' ' + angular.toJson(expected);
38282     var self = this;
38283     this.addFuture('expect ' + description,
38284       function(done) {
38285         var error;
38286         self.actual = self.future.value;
38287         if ((self.inverse && fn.call(self, expected)) ||
38288             (!self.inverse && !fn.call(self, expected))) {
38289           error = 'expected ' + description +
38290             ' but was ' + angular.toJson(self.actual);
38291         }
38292         done(error);
38293     });
38294   };
38295 };
38296
38297 /**
38298  * Initialize the scenario runner and run !
38299  *
38300  * Access global window and document object
38301  * Access $runner through closure
38302  *
38303  * @param {Object=} config Config options
38304  */
38305 angular.scenario.setUpAndRun = function(config) {
38306   var href = window.location.href;
38307   var body = _jQuery(document.body);
38308   var output = [];
38309   var objModel = new angular.scenario.ObjectModel($runner);
38310
38311   if (config && config.scenario_output) {
38312     output = config.scenario_output.split(',');
38313   }
38314
38315   angular.forEach(angular.scenario.output, function(fn, name) {
38316     if (!output.length || output.indexOf(name) != -1) {
38317       var context = body.append('<div></div>').find('div:last');
38318       context.attr('id', name);
38319       fn.call({}, context, $runner, objModel);
38320     }
38321   });
38322
38323   if (!/^http/.test(href) && !/^https/.test(href)) {
38324     body.append('<p id="system-error"></p>');
38325     body.find('#system-error').text(
38326       'Scenario runner must be run using http or https. The protocol ' +
38327       href.split(':')[0] + ':// is not supported.'
38328     );
38329     return;
38330   }
38331
38332   var appFrame = body.append('<div id="application"></div>').find('#application');
38333   var application = new angular.scenario.Application(appFrame);
38334
38335   $runner.on('RunnerEnd', function() {
38336     appFrame.css('display', 'none');
38337     appFrame.find('iframe').attr('src', 'about:blank');
38338   });
38339
38340   $runner.on('RunnerError', function(error) {
38341     if (window.console) {
38342       console.log(formatException(error));
38343     } else {
38344       // Do something for IE
38345       alert(error);
38346     }
38347   });
38348
38349   $runner.run(application);
38350 };
38351
38352 /**
38353  * Iterates through list with iterator function that must call the
38354  * continueFunction to continue iterating.
38355  *
38356  * @param {Array} list list to iterate over
38357  * @param {function()} iterator Callback function(value, continueFunction)
38358  * @param {function()} done Callback function(error, result) called when
38359  *   iteration finishes or an error occurs.
38360  */
38361 function asyncForEach(list, iterator, done) {
38362   var i = 0;
38363   function loop(error, index) {
38364     if (index && index > i) {
38365       i = index;
38366     }
38367     if (error || i >= list.length) {
38368       done(error);
38369     } else {
38370       try {
38371         iterator(list[i++], loop);
38372       } catch (e) {
38373         done(e);
38374       }
38375     }
38376   }
38377   loop();
38378 }
38379
38380 /**
38381  * Formats an exception into a string with the stack trace, but limits
38382  * to a specific line length.
38383  *
38384  * @param {Object} error The exception to format, can be anything throwable
38385  * @param {Number=} [maxStackLines=5] max lines of the stack trace to include
38386  *  default is 5.
38387  */
38388 function formatException(error, maxStackLines) {
38389   maxStackLines = maxStackLines || 5;
38390   var message = error.toString();
38391   if (error.stack) {
38392     var stack = error.stack.split('\n');
38393     if (stack[0].indexOf(message) === -1) {
38394       maxStackLines++;
38395       stack.unshift(error.message);
38396     }
38397     message = stack.slice(0, maxStackLines).join('\n');
38398   }
38399   return message;
38400 }
38401
38402 /**
38403  * Returns a function that gets the file name and line number from a
38404  * location in the stack if available based on the call site.
38405  *
38406  * Note: this returns another function because accessing .stack is very
38407  * expensive in Chrome.
38408  *
38409  * @param {Number} offset Number of stack lines to skip
38410  */
38411 function callerFile(offset) {
38412   var error = new Error();
38413
38414   return function() {
38415     var line = (error.stack || '').split('\n')[offset];
38416
38417     // Clean up the stack trace line
38418     if (line) {
38419       if (line.indexOf('@') !== -1) {
38420         // Firefox
38421         line = line.substring(line.indexOf('@') + 1);
38422       } else {
38423         // Chrome
38424         line = line.substring(line.indexOf('(') + 1).replace(')', '');
38425       }
38426     }
38427
38428     return line || '';
38429   };
38430 }
38431
38432
38433 /**
38434  * Don't use the jQuery trigger method since it works incorrectly.
38435  *
38436  * jQuery notifies listeners and then changes the state of a checkbox and
38437  * does not create a real browser event. A real click changes the state of
38438  * the checkbox and then notifies listeners.
38439  *
38440  * To work around this we instead use our own handler that fires a real event.
38441  */
38442 (function(fn) {
38443   // We need a handle to the original trigger function for input tests.
38444   var parentTrigger = fn._originalTrigger = fn.trigger;
38445   fn.trigger = function(type) {
38446     if (/(click|change|keydown|blur|input|mousedown|mouseup)/.test(type)) {
38447       var processDefaults = [];
38448       this.each(function(index, node) {
38449         processDefaults.push(browserTrigger(node, type));
38450       });
38451
38452       // this is not compatible with jQuery - we return an array of returned values,
38453       // so that scenario runner know whether JS code has preventDefault() of the event or not...
38454       return processDefaults;
38455     }
38456     return parentTrigger.apply(this, arguments);
38457   };
38458 })(_jQuery.fn);
38459
38460 /**
38461  * Finds all bindings with the substring match of name and returns an
38462  * array of their values.
38463  *
38464  * @param {string} bindExp The name to match
38465  * @return {Array.<string>} String of binding values
38466  */
38467 _jQuery.fn.bindings = function(windowJquery, bindExp) {
38468   var result = [], match,
38469       bindSelector = '.ng-binding:visible';
38470   if (angular.isString(bindExp)) {
38471     bindExp = bindExp.replace(/\s/g, '');
38472     match = function(actualExp) {
38473       if (actualExp) {
38474         actualExp = actualExp.replace(/\s/g, '');
38475         if (actualExp == bindExp) return true;
38476         if (actualExp.indexOf(bindExp) === 0) {
38477           return actualExp.charAt(bindExp.length) == '|';
38478         }
38479       }
38480     };
38481   } else if (bindExp) {
38482     match = function(actualExp) {
38483       return actualExp && bindExp.exec(actualExp);
38484     };
38485   } else {
38486     match = function(actualExp) {
38487       return !!actualExp;
38488     };
38489   }
38490   var selection = this.find(bindSelector);
38491   if (this.is(bindSelector)) {
38492     selection = selection.add(this);
38493   }
38494
38495   function push(value) {
38496     if (angular.isUndefined(value)) {
38497       value = '';
38498     } else if (typeof value !== 'string') {
38499       value = angular.toJson(value);
38500     }
38501     result.push('' + value);
38502   }
38503
38504   selection.each(function() {
38505     var element = windowJquery(this),
38506         bindings;
38507     if (bindings = element.data('$binding')) {
38508       for (var expressions = [], binding, j=0, jj=bindings.length; j < jj; j++) {
38509         binding = bindings[j];
38510
38511         if (binding.expressions) {
38512           expressions = binding.expressions;
38513         } else {
38514           expressions = [binding];
38515         }
38516         for (var scope, expression, i = 0, ii = expressions.length; i < ii; i++) {
38517           expression = expressions[i];
38518           if (match(expression)) {
38519             scope = scope || element.scope();
38520             push(scope.$eval(expression));
38521           }
38522         }
38523       }
38524     }
38525   });
38526   return result;
38527 };
38528
38529 (function() {
38530   /**
38531    * Triggers a browser event. Attempts to choose the right event if one is
38532    * not specified.
38533    *
38534    * @param {Object} element Either a wrapped jQuery/jqLite node or a DOMElement
38535    * @param {string} eventType Optional event type
38536    * @param {Object=} eventData An optional object which contains additional event data (such as x,y
38537    * coordinates, keys, etc...) that are passed into the event when triggered
38538    */
38539   window.browserTrigger = function browserTrigger(element, eventType, eventData) {
38540     if (element && !element.nodeName) element = element[0];
38541     if (!element) return;
38542
38543     eventData = eventData || {};
38544     var relatedTarget = eventData.relatedTarget || element;
38545     var keys = eventData.keys;
38546     var x = eventData.x;
38547     var y = eventData.y;
38548
38549     var inputType = (element.type) ? element.type.toLowerCase() : null,
38550         nodeName = element.nodeName.toLowerCase();
38551     if (!eventType) {
38552       eventType = {
38553         'text':            'change',
38554         'textarea':        'change',
38555         'hidden':          'change',
38556         'password':        'change',
38557         'button':          'click',
38558         'submit':          'click',
38559         'reset':           'click',
38560         'image':           'click',
38561         'checkbox':        'click',
38562         'radio':           'click',
38563         'select-one':      'change',
38564         'select-multiple': 'change',
38565         '_default_':       'click'
38566       }[inputType || '_default_'];
38567     }
38568
38569     if (nodeName == 'option') {
38570       element.parentNode.value = element.value;
38571       element = element.parentNode;
38572       eventType = 'change';
38573     }
38574
38575     keys = keys || [];
38576     function pressed(key) {
38577       return keys.indexOf(key) !== -1;
38578     }
38579
38580     var evnt;
38581     if (/transitionend/.test(eventType)) {
38582       if (window.WebKitTransitionEvent) {
38583         evnt = new WebKitTransitionEvent(eventType, eventData);
38584         evnt.initEvent(eventType, false, true);
38585       } else {
38586         try {
38587           evnt = new TransitionEvent(eventType, eventData);
38588         }
38589         catch (e) {
38590           evnt = document.createEvent('TransitionEvent');
38591           evnt.initTransitionEvent(eventType, null, null, null, eventData.elapsedTime || 0);
38592         }
38593       }
38594     } else if (/animationend/.test(eventType)) {
38595       if (window.WebKitAnimationEvent) {
38596         evnt = new WebKitAnimationEvent(eventType, eventData);
38597         evnt.initEvent(eventType, false, true);
38598       } else {
38599         try {
38600           evnt = new AnimationEvent(eventType, eventData);
38601         }
38602         catch (e) {
38603           evnt = document.createEvent('AnimationEvent');
38604           evnt.initAnimationEvent(eventType, null, null, null, eventData.elapsedTime || 0);
38605         }
38606       }
38607     } else if (/touch/.test(eventType) && supportsTouchEvents()) {
38608       evnt = createTouchEvent(element, eventType, x, y);
38609     } else {
38610       evnt = document.createEvent('MouseEvents');
38611       x = x || 0;
38612       y = y || 0;
38613       evnt.initMouseEvent(eventType, true, true, window, 0, x, y, x, y, pressed('ctrl'),
38614           pressed('alt'), pressed('shift'), pressed('meta'), 0, relatedTarget);
38615     }
38616
38617     /* we're unable to change the timeStamp value directly so this
38618      * is only here to allow for testing where the timeStamp value is
38619      * read */
38620     evnt.$manualTimeStamp = eventData.timeStamp;
38621
38622     if (!evnt) return;
38623
38624     var originalPreventDefault = evnt.preventDefault,
38625         appWindow = element.ownerDocument.defaultView,
38626         fakeProcessDefault = true,
38627         finalProcessDefault,
38628         angular = appWindow.angular || {};
38629
38630     // igor: temporary fix for https://bugzilla.mozilla.org/show_bug.cgi?id=684208
38631     angular['ff-684208-preventDefault'] = false;
38632     evnt.preventDefault = function() {
38633       fakeProcessDefault = false;
38634       return originalPreventDefault.apply(evnt, arguments);
38635     };
38636
38637     element.dispatchEvent(evnt);
38638     finalProcessDefault = !(angular['ff-684208-preventDefault'] || !fakeProcessDefault);
38639
38640     delete angular['ff-684208-preventDefault'];
38641
38642     return finalProcessDefault;
38643   };
38644
38645   function supportsTouchEvents() {
38646     if ('_cached' in supportsTouchEvents) {
38647       return supportsTouchEvents._cached;
38648     }
38649     if (!document.createTouch || !document.createTouchList) {
38650       supportsTouchEvents._cached = false;
38651       return false;
38652     }
38653     try {
38654       document.createEvent('TouchEvent');
38655     } catch (e) {
38656       supportsTouchEvents._cached = false;
38657       return false;
38658     }
38659     supportsTouchEvents._cached = true;
38660     return true;
38661   }
38662
38663   function createTouchEvent(element, eventType, x, y) {
38664     var evnt = new Event(eventType);
38665     x = x || 0;
38666     y = y || 0;
38667
38668     var touch = document.createTouch(window, element, Date.now(), x, y, x, y);
38669     var touches = document.createTouchList(touch);
38670
38671     evnt.touches = touches;
38672
38673     return evnt;
38674   }
38675 }());
38676
38677 /**
38678  * Represents the application currently being tested and abstracts usage
38679  * of iframes or separate windows.
38680  *
38681  * @param {Object} context jQuery wrapper around HTML context.
38682  */
38683 angular.scenario.Application = function(context) {
38684   this.context = context;
38685   context.append(
38686     '<h2>Current URL: <a href="about:blank">None</a></h2>' +
38687     '<div id="test-frames"></div>'
38688   );
38689 };
38690
38691 /**
38692  * Gets the jQuery collection of frames. Don't use this directly because
38693  * frames may go stale.
38694  *
38695  * @private
38696  * @return {Object} jQuery collection
38697  */
38698 angular.scenario.Application.prototype.getFrame_ = function() {
38699   return this.context.find('#test-frames iframe:last');
38700 };
38701
38702 /**
38703  * Gets the window of the test runner frame. Always favor executeAction()
38704  * instead of this method since it prevents you from getting a stale window.
38705  *
38706  * @private
38707  * @return {Object} the window of the frame
38708  */
38709 angular.scenario.Application.prototype.getWindow_ = function() {
38710   var contentWindow = this.getFrame_().prop('contentWindow');
38711   if (!contentWindow) {
38712     throw 'Frame window is not accessible.';
38713   }
38714   return contentWindow;
38715 };
38716
38717 /**
38718  * Changes the location of the frame.
38719  *
38720  * @param {string} url The URL. If it begins with a # then only the
38721  *   hash of the page is changed.
38722  * @param {function()} loadFn function($window, $document) Called when frame loads.
38723  * @param {function()} errorFn function(error) Called if any error when loading.
38724  */
38725 angular.scenario.Application.prototype.navigateTo = function(url, loadFn, errorFn) {
38726   var self = this;
38727   var frame = self.getFrame_();
38728   //TODO(esprehn): Refactor to use rethrow()
38729   errorFn = errorFn || function(e) { throw e; };
38730   if (url === 'about:blank') {
38731     errorFn('Sandbox Error: Navigating to about:blank is not allowed.');
38732   } else if (url.charAt(0) === '#') {
38733     url = frame.attr('src').split('#')[0] + url;
38734     frame.attr('src', url);
38735     self.executeAction(loadFn);
38736   } else {
38737     frame.remove();
38738     self.context.find('#test-frames').append('<iframe>');
38739     frame = self.getFrame_();
38740
38741     frame.load(function() {
38742       frame.off();
38743       try {
38744         var $window = self.getWindow_();
38745
38746         if (!$window.angular) {
38747           self.executeAction(loadFn);
38748           return;
38749         }
38750
38751         if (!$window.angular.resumeBootstrap) {
38752           $window.angular.resumeDeferredBootstrap = resumeDeferredBootstrap;
38753         } else {
38754           resumeDeferredBootstrap();
38755         }
38756
38757       } catch (e) {
38758         errorFn(e);
38759       }
38760
38761       function resumeDeferredBootstrap() {
38762         // Disable animations
38763         var $injector = $window.angular.resumeBootstrap([['$provide', function($provide) {
38764           return ['$animate', function($animate) {
38765             $animate.enabled(false);
38766           }];
38767         }]]);
38768         self.rootElement = $injector.get('$rootElement')[0];
38769         self.executeAction(loadFn);
38770       }
38771     }).attr('src', url);
38772
38773     // for IE compatibility set the name *after* setting the frame url
38774     frame[0].contentWindow.name = "NG_DEFER_BOOTSTRAP!";
38775   }
38776   self.context.find('> h2 a').attr('href', url).text(url);
38777 };
38778
38779 /**
38780  * Executes a function in the context of the tested application. Will wait
38781  * for all pending angular xhr requests before executing.
38782  *
38783  * @param {function()} action The callback to execute. function($window, $document)
38784  *  $document is a jQuery wrapped document.
38785  */
38786 angular.scenario.Application.prototype.executeAction = function(action) {
38787   var self = this;
38788   var $window = this.getWindow_();
38789   if (!$window.document) {
38790     throw 'Sandbox Error: Application document not accessible.';
38791   }
38792   if (!$window.angular) {
38793     return action.call(this, $window, _jQuery($window.document));
38794   }
38795
38796   if (!!this.rootElement) {
38797     executeWithElement(this.rootElement);
38798   } else {
38799     angularInit($window.document, angular.bind(this, executeWithElement));
38800   }
38801
38802   function executeWithElement(element) {
38803     var $injector = $window.angular.element(element).injector();
38804     var $element = _jQuery(element);
38805
38806     $element.injector = function() {
38807       return $injector;
38808     };
38809
38810     $injector.invoke(function($browser) {
38811       $browser.notifyWhenNoOutstandingRequests(function() {
38812         action.call(self, $window, $element);
38813       });
38814     });
38815   }
38816 };
38817
38818 /**
38819  * The representation of define blocks. Don't used directly, instead use
38820  * define() in your tests.
38821  *
38822  * @param {string} descName Name of the block
38823  * @param {Object} parent describe or undefined if the root.
38824  */
38825 angular.scenario.Describe = function(descName, parent) {
38826   this.only = parent && parent.only;
38827   this.beforeEachFns = [];
38828   this.afterEachFns = [];
38829   this.its = [];
38830   this.children = [];
38831   this.name = descName;
38832   this.parent = parent;
38833   this.id = angular.scenario.Describe.id++;
38834
38835   /**
38836    * Calls all before functions.
38837    */
38838   var beforeEachFns = this.beforeEachFns;
38839   this.setupBefore = function() {
38840     if (parent) parent.setupBefore.call(this);
38841     angular.forEach(beforeEachFns, function(fn) { fn.call(this); }, this);
38842   };
38843
38844   /**
38845    * Calls all after functions.
38846    */
38847   var afterEachFns = this.afterEachFns;
38848   this.setupAfter  = function() {
38849     angular.forEach(afterEachFns, function(fn) { fn.call(this); }, this);
38850     if (parent) parent.setupAfter.call(this);
38851   };
38852 };
38853
38854 // Shared Unique ID generator for every describe block
38855 angular.scenario.Describe.id = 0;
38856
38857 // Shared Unique ID generator for every it (spec)
38858 angular.scenario.Describe.specId = 0;
38859
38860 /**
38861  * Defines a block to execute before each it or nested describe.
38862  *
38863  * @param {function()} body Body of the block.
38864  */
38865 angular.scenario.Describe.prototype.beforeEach = function(body) {
38866   this.beforeEachFns.push(body);
38867 };
38868
38869 /**
38870  * Defines a block to execute after each it or nested describe.
38871  *
38872  * @param {function()} body Body of the block.
38873  */
38874 angular.scenario.Describe.prototype.afterEach = function(body) {
38875   this.afterEachFns.push(body);
38876 };
38877
38878 /**
38879  * Creates a new describe block that's a child of this one.
38880  *
38881  * @param {string} name Name of the block. Appended to the parent block's name.
38882  * @param {function()} body Body of the block.
38883  */
38884 angular.scenario.Describe.prototype.describe = function(name, body) {
38885   var child = new angular.scenario.Describe(name, this);
38886   this.children.push(child);
38887   body.call(child);
38888 };
38889
38890 /**
38891  * Same as describe() but makes ddescribe blocks the only to run.
38892  *
38893  * @param {string} name Name of the test.
38894  * @param {function()} body Body of the block.
38895  */
38896 angular.scenario.Describe.prototype.ddescribe = function(name, body) {
38897   var child = new angular.scenario.Describe(name, this);
38898   child.only = true;
38899   this.children.push(child);
38900   body.call(child);
38901 };
38902
38903 /**
38904  * Use to disable a describe block.
38905  */
38906 angular.scenario.Describe.prototype.xdescribe = angular.noop;
38907
38908 /**
38909  * Defines a test.
38910  *
38911  * @param {string} name Name of the test.
38912  * @param {function()} body Body of the block.
38913  */
38914 angular.scenario.Describe.prototype.it = function(name, body) {
38915   this.its.push({
38916     id: angular.scenario.Describe.specId++,
38917     definition: this,
38918     only: this.only,
38919     name: name,
38920     before: this.setupBefore,
38921     body: body,
38922     after: this.setupAfter
38923   });
38924 };
38925
38926 /**
38927  * Same as it() but makes iit tests the only test to run.
38928  *
38929  * @param {string} name Name of the test.
38930  * @param {function()} body Body of the block.
38931  */
38932 angular.scenario.Describe.prototype.iit = function(name, body) {
38933   this.it.apply(this, arguments);
38934   this.its[this.its.length - 1].only = true;
38935 };
38936
38937 /**
38938  * Use to disable a test block.
38939  */
38940 angular.scenario.Describe.prototype.xit = angular.noop;
38941
38942 /**
38943  * Gets an array of functions representing all the tests (recursively).
38944  * that can be executed with SpecRunner's.
38945  *
38946  * @return {Array<Object>} Array of it blocks {
38947  *   definition : Object // parent Describe
38948  *   only: boolean
38949  *   name: string
38950  *   before: Function
38951  *   body: Function
38952  *   after: Function
38953  *  }
38954  */
38955 angular.scenario.Describe.prototype.getSpecs = function() {
38956   var specs = arguments[0] || [];
38957   angular.forEach(this.children, function(child) {
38958     child.getSpecs(specs);
38959   });
38960   angular.forEach(this.its, function(it) {
38961     specs.push(it);
38962   });
38963   var only = [];
38964   angular.forEach(specs, function(it) {
38965     if (it.only) {
38966       only.push(it);
38967     }
38968   });
38969   return (only.length && only) || specs;
38970 };
38971
38972 /**
38973  * A future action in a spec.
38974  *
38975  * @param {string} name name of the future action
38976  * @param {function()} behavior future callback(error, result)
38977  * @param {function()} line Optional. function that returns the file/line number.
38978  */
38979 angular.scenario.Future = function(name, behavior, line) {
38980   this.name = name;
38981   this.behavior = behavior;
38982   this.fulfilled = false;
38983   this.value = undefined;
38984   this.parser = angular.identity;
38985   this.line = line || function() { return ''; };
38986 };
38987
38988 /**
38989  * Executes the behavior of the closure.
38990  *
38991  * @param {function()} doneFn Callback function(error, result)
38992  */
38993 angular.scenario.Future.prototype.execute = function(doneFn) {
38994   var self = this;
38995   this.behavior(function(error, result) {
38996     self.fulfilled = true;
38997     if (result) {
38998       try {
38999         result = self.parser(result);
39000       } catch (e) {
39001         error = e;
39002       }
39003     }
39004     self.value = error || result;
39005     doneFn(error, result);
39006   });
39007 };
39008
39009 /**
39010  * Configures the future to convert its final with a function fn(value)
39011  *
39012  * @param {function()} fn function(value) that returns the parsed value
39013  */
39014 angular.scenario.Future.prototype.parsedWith = function(fn) {
39015   this.parser = fn;
39016   return this;
39017 };
39018
39019 /**
39020  * Configures the future to parse its final value from JSON
39021  * into objects.
39022  */
39023 angular.scenario.Future.prototype.fromJson = function() {
39024   return this.parsedWith(angular.fromJson);
39025 };
39026
39027 /**
39028  * Configures the future to convert its final value from objects
39029  * into JSON.
39030  */
39031 angular.scenario.Future.prototype.toJson = function() {
39032   return this.parsedWith(angular.toJson);
39033 };
39034
39035 /**
39036  * Maintains an object tree from the runner events.
39037  *
39038  * @param {Object} runner The scenario Runner instance to connect to.
39039  *
39040  * TODO(esprehn): Every output type creates one of these, but we probably
39041  *  want one global shared instance. Need to handle events better too
39042  *  so the HTML output doesn't need to do spec model.getSpec(spec.id)
39043  *  silliness.
39044  *
39045  * TODO(vojta) refactor on, emit methods (from all objects) - use inheritance
39046  */
39047 angular.scenario.ObjectModel = function(runner) {
39048   var self = this;
39049
39050   this.specMap = {};
39051   this.listeners = [];
39052   this.value = {
39053     name: '',
39054     children: {}
39055   };
39056
39057   runner.on('SpecBegin', function(spec) {
39058     var block = self.value,
39059         definitions = [];
39060
39061     angular.forEach(self.getDefinitionPath(spec), function(def) {
39062       if (!block.children[def.name]) {
39063         block.children[def.name] = {
39064           id: def.id,
39065           name: def.name,
39066           children: {},
39067           specs: {}
39068         };
39069       }
39070       block = block.children[def.name];
39071       definitions.push(def.name);
39072     });
39073
39074     var it = self.specMap[spec.id] =
39075              block.specs[spec.name] =
39076              new angular.scenario.ObjectModel.Spec(spec.id, spec.name, definitions);
39077
39078     // forward the event
39079     self.emit('SpecBegin', it);
39080   });
39081
39082   runner.on('SpecError', function(spec, error) {
39083     var it = self.getSpec(spec.id);
39084     it.status = 'error';
39085     it.error = error;
39086
39087     // forward the event
39088     self.emit('SpecError', it, error);
39089   });
39090
39091   runner.on('SpecEnd', function(spec) {
39092     var it = self.getSpec(spec.id);
39093     complete(it);
39094
39095     // forward the event
39096     self.emit('SpecEnd', it);
39097   });
39098
39099   runner.on('StepBegin', function(spec, step) {
39100     var it = self.getSpec(spec.id);
39101     step = new angular.scenario.ObjectModel.Step(step.name);
39102     it.steps.push(step);
39103
39104     // forward the event
39105     self.emit('StepBegin', it, step);
39106   });
39107
39108   runner.on('StepEnd', function(spec) {
39109     var it = self.getSpec(spec.id);
39110     var step = it.getLastStep();
39111     if (step.name !== step.name) {
39112       throw 'Events fired in the wrong order. Step names don\'t match.';
39113     }
39114     complete(step);
39115
39116     // forward the event
39117     self.emit('StepEnd', it, step);
39118   });
39119
39120   runner.on('StepFailure', function(spec, step, error) {
39121     var it = self.getSpec(spec.id),
39122         modelStep = it.getLastStep();
39123
39124     modelStep.setErrorStatus('failure', error, step.line());
39125     it.setStatusFromStep(modelStep);
39126
39127     // forward the event
39128     self.emit('StepFailure', it, modelStep, error);
39129   });
39130
39131   runner.on('StepError', function(spec, step, error) {
39132     var it = self.getSpec(spec.id),
39133         modelStep = it.getLastStep();
39134
39135     modelStep.setErrorStatus('error', error, step.line());
39136     it.setStatusFromStep(modelStep);
39137
39138     // forward the event
39139     self.emit('StepError', it, modelStep, error);
39140   });
39141
39142   runner.on('RunnerBegin', function() {
39143     self.emit('RunnerBegin');
39144   });
39145   runner.on('RunnerEnd', function() {
39146     self.emit('RunnerEnd');
39147   });
39148
39149   function complete(item) {
39150     item.endTime = Date.now();
39151     item.duration = item.endTime - item.startTime;
39152     item.status = item.status || 'success';
39153   }
39154 };
39155
39156 /**
39157  * Adds a listener for an event.
39158  *
39159  * @param {string} eventName Name of the event to add a handler for
39160  * @param {function()} listener Function that will be called when event is fired
39161  */
39162 angular.scenario.ObjectModel.prototype.on = function(eventName, listener) {
39163   eventName = eventName.toLowerCase();
39164   this.listeners[eventName] = this.listeners[eventName] || [];
39165   this.listeners[eventName].push(listener);
39166 };
39167
39168 /**
39169  * Emits an event which notifies listeners and passes extra
39170  * arguments.
39171  *
39172  * @param {string} eventName Name of the event to fire.
39173  */
39174 angular.scenario.ObjectModel.prototype.emit = function(eventName) {
39175   var self = this,
39176       args = Array.prototype.slice.call(arguments, 1);
39177
39178   eventName = eventName.toLowerCase();
39179
39180   if (this.listeners[eventName]) {
39181     angular.forEach(this.listeners[eventName], function(listener) {
39182       listener.apply(self, args);
39183     });
39184   }
39185 };
39186
39187 /**
39188  * Computes the path of definition describe blocks that wrap around
39189  * this spec.
39190  *
39191  * @param spec Spec to compute the path for.
39192  * @return {Array<Describe>} The describe block path
39193  */
39194 angular.scenario.ObjectModel.prototype.getDefinitionPath = function(spec) {
39195   var path = [];
39196   var currentDefinition = spec.definition;
39197   while (currentDefinition && currentDefinition.name) {
39198     path.unshift(currentDefinition);
39199     currentDefinition = currentDefinition.parent;
39200   }
39201   return path;
39202 };
39203
39204 /**
39205  * Gets a spec by id.
39206  *
39207  * @param {string} id The id of the spec to get the object for.
39208  * @return {Object} the Spec instance
39209  */
39210 angular.scenario.ObjectModel.prototype.getSpec = function(id) {
39211   return this.specMap[id];
39212 };
39213
39214 /**
39215  * A single it block.
39216  *
39217  * @param {string} id Id of the spec
39218  * @param {string} name Name of the spec
39219  * @param {Array<string>=} definitionNames List of all describe block names that wrap this spec
39220  */
39221 angular.scenario.ObjectModel.Spec = function(id, name, definitionNames) {
39222   this.id = id;
39223   this.name = name;
39224   this.startTime = Date.now();
39225   this.steps = [];
39226   this.fullDefinitionName = (definitionNames || []).join(' ');
39227 };
39228
39229 /**
39230  * Adds a new step to the Spec.
39231  *
39232  * @param {string} name Name of the step (really name of the future)
39233  * @return {Object} the added step
39234  */
39235 angular.scenario.ObjectModel.Spec.prototype.addStep = function(name) {
39236   var step = new angular.scenario.ObjectModel.Step(name);
39237   this.steps.push(step);
39238   return step;
39239 };
39240
39241 /**
39242  * Gets the most recent step.
39243  *
39244  * @return {Object} the step
39245  */
39246 angular.scenario.ObjectModel.Spec.prototype.getLastStep = function() {
39247   return this.steps[this.steps.length - 1];
39248 };
39249
39250 /**
39251  * Set status of the Spec from given Step
39252  *
39253  * @param {angular.scenario.ObjectModel.Step} step
39254  */
39255 angular.scenario.ObjectModel.Spec.prototype.setStatusFromStep = function(step) {
39256   if (!this.status || step.status == 'error') {
39257     this.status = step.status;
39258     this.error = step.error;
39259     this.line = step.line;
39260   }
39261 };
39262
39263 /**
39264  * A single step inside a Spec.
39265  *
39266  * @param {string} name Name of the step
39267  */
39268 angular.scenario.ObjectModel.Step = function(name) {
39269   this.name = name;
39270   this.startTime = Date.now();
39271 };
39272
39273 /**
39274  * Helper method for setting all error status related properties
39275  *
39276  * @param {string} status
39277  * @param {string} error
39278  * @param {string} line
39279  */
39280 angular.scenario.ObjectModel.Step.prototype.setErrorStatus = function(status, error, line) {
39281   this.status = status;
39282   this.error = error;
39283   this.line = line;
39284 };
39285
39286 /**
39287  * Runner for scenarios
39288  *
39289  * Has to be initialized before any test is loaded,
39290  * because it publishes the API into window (global space).
39291  */
39292 angular.scenario.Runner = function($window) {
39293   this.listeners = [];
39294   this.$window = $window;
39295   this.rootDescribe = new angular.scenario.Describe();
39296   this.currentDescribe = this.rootDescribe;
39297   this.api = {
39298     it: this.it,
39299     iit: this.iit,
39300     xit: angular.noop,
39301     describe: this.describe,
39302     ddescribe: this.ddescribe,
39303     xdescribe: angular.noop,
39304     beforeEach: this.beforeEach,
39305     afterEach: this.afterEach
39306   };
39307   angular.forEach(this.api, angular.bind(this, function(fn, key) {
39308     this.$window[key] = angular.bind(this, fn);
39309   }));
39310 };
39311
39312 /**
39313  * Emits an event which notifies listeners and passes extra
39314  * arguments.
39315  *
39316  * @param {string} eventName Name of the event to fire.
39317  */
39318 angular.scenario.Runner.prototype.emit = function(eventName) {
39319   var self = this;
39320   var args = Array.prototype.slice.call(arguments, 1);
39321   eventName = eventName.toLowerCase();
39322   if (!this.listeners[eventName]) {
39323     return;
39324   }
39325   angular.forEach(this.listeners[eventName], function(listener) {
39326     listener.apply(self, args);
39327   });
39328 };
39329
39330 /**
39331  * Adds a listener for an event.
39332  *
39333  * @param {string} eventName The name of the event to add a handler for
39334  * @param {string} listener The fn(...) that takes the extra arguments from emit()
39335  */
39336 angular.scenario.Runner.prototype.on = function(eventName, listener) {
39337   eventName = eventName.toLowerCase();
39338   this.listeners[eventName] = this.listeners[eventName] || [];
39339   this.listeners[eventName].push(listener);
39340 };
39341
39342 /**
39343  * Defines a describe block of a spec.
39344  *
39345  * @see Describe.js
39346  *
39347  * @param {string} name Name of the block
39348  * @param {function()} body Body of the block
39349  */
39350 angular.scenario.Runner.prototype.describe = function(name, body) {
39351   var self = this;
39352   this.currentDescribe.describe(name, function() {
39353     var parentDescribe = self.currentDescribe;
39354     self.currentDescribe = this;
39355     try {
39356       body.call(this);
39357     } finally {
39358       self.currentDescribe = parentDescribe;
39359     }
39360   });
39361 };
39362
39363 /**
39364  * Same as describe, but makes ddescribe the only blocks to run.
39365  *
39366  * @see Describe.js
39367  *
39368  * @param {string} name Name of the block
39369  * @param {function()} body Body of the block
39370  */
39371 angular.scenario.Runner.prototype.ddescribe = function(name, body) {
39372   var self = this;
39373   this.currentDescribe.ddescribe(name, function() {
39374     var parentDescribe = self.currentDescribe;
39375     self.currentDescribe = this;
39376     try {
39377       body.call(this);
39378     } finally {
39379       self.currentDescribe = parentDescribe;
39380     }
39381   });
39382 };
39383
39384 /**
39385  * Defines a test in a describe block of a spec.
39386  *
39387  * @see Describe.js
39388  *
39389  * @param {string} name Name of the block
39390  * @param {function()} body Body of the block
39391  */
39392 angular.scenario.Runner.prototype.it = function(name, body) {
39393   this.currentDescribe.it(name, body);
39394 };
39395
39396 /**
39397  * Same as it, but makes iit tests the only tests to run.
39398  *
39399  * @see Describe.js
39400  *
39401  * @param {string} name Name of the block
39402  * @param {function()} body Body of the block
39403  */
39404 angular.scenario.Runner.prototype.iit = function(name, body) {
39405   this.currentDescribe.iit(name, body);
39406 };
39407
39408 /**
39409  * Defines a function to be called before each it block in the describe
39410  * (and before all nested describes).
39411  *
39412  * @see Describe.js
39413  *
39414  * @param {function()} Callback to execute
39415  */
39416 angular.scenario.Runner.prototype.beforeEach = function(body) {
39417   this.currentDescribe.beforeEach(body);
39418 };
39419
39420 /**
39421  * Defines a function to be called after each it block in the describe
39422  * (and before all nested describes).
39423  *
39424  * @see Describe.js
39425  *
39426  * @param {function()} Callback to execute
39427  */
39428 angular.scenario.Runner.prototype.afterEach = function(body) {
39429   this.currentDescribe.afterEach(body);
39430 };
39431
39432 /**
39433  * Creates a new spec runner.
39434  *
39435  * @private
39436  * @param {Object} scope parent scope
39437  */
39438 angular.scenario.Runner.prototype.createSpecRunner_ = function(scope) {
39439   var child = scope.$new();
39440   var Cls = angular.scenario.SpecRunner;
39441
39442   // Export all the methods to child scope manually as now we don't mess controllers with scopes
39443   // TODO(vojta): refactor scenario runner so that these objects are not tightly coupled as current
39444   for (var name in Cls.prototype) {
39445     child[name] = angular.bind(child, Cls.prototype[name]);
39446   }
39447
39448   Cls.call(child);
39449   return child;
39450 };
39451
39452 /**
39453  * Runs all the loaded tests with the specified runner class on the
39454  * provided application.
39455  *
39456  * @param {angular.scenario.Application} application App to remote control.
39457  */
39458 angular.scenario.Runner.prototype.run = function(application) {
39459   var self = this;
39460   var $root = angular.injector(['ng']).get('$rootScope');
39461   angular.extend($root, this);
39462   angular.forEach(angular.scenario.Runner.prototype, function(fn, name) {
39463     $root[name] = angular.bind(self, fn);
39464   });
39465   $root.application = application;
39466   $root.emit('RunnerBegin');
39467   asyncForEach(this.rootDescribe.getSpecs(), function(spec, specDone) {
39468     var dslCache = {};
39469     var runner = self.createSpecRunner_($root);
39470     angular.forEach(angular.scenario.dsl, function(fn, key) {
39471       dslCache[key] = fn.call($root);
39472     });
39473     angular.forEach(angular.scenario.dsl, function(fn, key) {
39474       self.$window[key] = function() {
39475         var line = callerFile(3);
39476         var scope = runner.$new();
39477
39478         // Make the dsl accessible on the current chain
39479         scope.dsl = {};
39480         angular.forEach(dslCache, function(fn, key) {
39481           scope.dsl[key] = function() {
39482             return dslCache[key].apply(scope, arguments);
39483           };
39484         });
39485
39486         // Make these methods work on the current chain
39487         scope.addFuture = function() {
39488           Array.prototype.push.call(arguments, line);
39489           return angular.scenario.SpecRunner.
39490             prototype.addFuture.apply(scope, arguments);
39491         };
39492         scope.addFutureAction = function() {
39493           Array.prototype.push.call(arguments, line);
39494           return angular.scenario.SpecRunner.
39495             prototype.addFutureAction.apply(scope, arguments);
39496         };
39497
39498         return scope.dsl[key].apply(scope, arguments);
39499       };
39500     });
39501     runner.run(spec, function() {
39502       runner.$destroy();
39503       specDone.apply(this, arguments);
39504     });
39505   },
39506   function(error) {
39507     if (error) {
39508       self.emit('RunnerError', error);
39509     }
39510     self.emit('RunnerEnd');
39511   });
39512 };
39513
39514 /**
39515  * This class is the "this" of the it/beforeEach/afterEach method.
39516  * Responsibilities:
39517  *   - "this" for it/beforeEach/afterEach
39518  *   - keep state for single it/beforeEach/afterEach execution
39519  *   - keep track of all of the futures to execute
39520  *   - run single spec (execute each future)
39521  */
39522 angular.scenario.SpecRunner = function() {
39523   this.futures = [];
39524   this.afterIndex = 0;
39525 };
39526
39527 /**
39528  * Executes a spec which is an it block with associated before/after functions
39529  * based on the describe nesting.
39530  *
39531  * @param {Object} spec A spec object
39532  * @param {function()} specDone function that is called when the spec finishes,
39533  *                              of the form `Function(error, index)`
39534  */
39535 angular.scenario.SpecRunner.prototype.run = function(spec, specDone) {
39536   var self = this;
39537   this.spec = spec;
39538
39539   this.emit('SpecBegin', spec);
39540
39541   try {
39542     spec.before.call(this);
39543     spec.body.call(this);
39544     this.afterIndex = this.futures.length;
39545     spec.after.call(this);
39546   } catch (e) {
39547     this.emit('SpecError', spec, e);
39548     this.emit('SpecEnd', spec);
39549     specDone();
39550     return;
39551   }
39552
39553   var handleError = function(error, done) {
39554     if (self.error) {
39555       return done();
39556     }
39557     self.error = true;
39558     done(null, self.afterIndex);
39559   };
39560
39561   asyncForEach(
39562     this.futures,
39563     function(future, futureDone) {
39564       self.step = future;
39565       self.emit('StepBegin', spec, future);
39566       try {
39567         future.execute(function(error) {
39568           if (error) {
39569             self.emit('StepFailure', spec, future, error);
39570             self.emit('StepEnd', spec, future);
39571             return handleError(error, futureDone);
39572           }
39573           self.emit('StepEnd', spec, future);
39574           self.$window.setTimeout(function() { futureDone(); }, 0);
39575         });
39576       } catch (e) {
39577         self.emit('StepError', spec, future, e);
39578         self.emit('StepEnd', spec, future);
39579         handleError(e, futureDone);
39580       }
39581     },
39582     function(e) {
39583       if (e) {
39584         self.emit('SpecError', spec, e);
39585       }
39586       self.emit('SpecEnd', spec);
39587       // Call done in a timeout so exceptions don't recursively
39588       // call this function
39589       self.$window.setTimeout(function() { specDone(); }, 0);
39590     }
39591   );
39592 };
39593
39594 /**
39595  * Adds a new future action.
39596  *
39597  * Note: Do not pass line manually. It happens automatically.
39598  *
39599  * @param {string} name Name of the future
39600  * @param {function()} behavior Behavior of the future
39601  * @param {function()} line fn() that returns file/line number
39602  */
39603 angular.scenario.SpecRunner.prototype.addFuture = function(name, behavior, line) {
39604   var future = new angular.scenario.Future(name, angular.bind(this, behavior), line);
39605   this.futures.push(future);
39606   return future;
39607 };
39608
39609 /**
39610  * Adds a new future action to be executed on the application window.
39611  *
39612  * Note: Do not pass line manually. It happens automatically.
39613  *
39614  * @param {string} name Name of the future
39615  * @param {function()} behavior Behavior of the future
39616  * @param {function()} line fn() that returns file/line number
39617  */
39618 angular.scenario.SpecRunner.prototype.addFutureAction = function(name, behavior, line) {
39619   var self = this;
39620   var NG = /\[ng\\\:/;
39621   return this.addFuture(name, function(done) {
39622     this.application.executeAction(function($window, $document) {
39623
39624       //TODO(esprehn): Refactor this so it doesn't need to be in here.
39625       $document.elements = function(selector) {
39626         var args = Array.prototype.slice.call(arguments, 1);
39627         selector = (self.selector || '') + ' ' + (selector || '');
39628         selector = _jQuery.trim(selector) || '*';
39629         angular.forEach(args, function(value, index) {
39630           selector = selector.replace('$' + (index + 1), value);
39631         });
39632         var result = $document.find(selector);
39633         if (selector.match(NG)) {
39634           angular.forEach(['[ng-','[data-ng-','[x-ng-'], function(value, index) {
39635             result = result.add(selector.replace(NG, value), $document);
39636           });
39637         }
39638         if (!result.length) {
39639           throw {
39640             type: 'selector',
39641             message: 'Selector ' + selector + ' did not match any elements.'
39642           };
39643         }
39644
39645         return result;
39646       };
39647
39648       try {
39649         behavior.call(self, $window, $document, done);
39650       } catch (e) {
39651         if (e.type && e.type === 'selector') {
39652           done(e.message);
39653         } else {
39654           throw e;
39655         }
39656       }
39657     });
39658   }, line);
39659 };
39660
39661 /**
39662  * Shared DSL statements that are useful to all scenarios.
39663  */
39664
39665  /**
39666  * Usage:
39667  *    pause() pauses until you call resume() in the console
39668  */
39669 angular.scenario.dsl('pause', function() {
39670   return function() {
39671     return this.addFuture('pausing for you to resume', function(done) {
39672       this.emit('InteractivePause', this.spec, this.step);
39673       this.$window.resume = function() { done(); };
39674     });
39675   };
39676 });
39677
39678 /**
39679  * Usage:
39680  *    sleep(seconds) pauses the test for specified number of seconds
39681  */
39682 angular.scenario.dsl('sleep', function() {
39683   return function(time) {
39684     return this.addFuture('sleep for ' + time + ' seconds', function(done) {
39685       this.$window.setTimeout(function() { done(null, time * 1000); }, time * 1000);
39686     });
39687   };
39688 });
39689
39690 /**
39691  * Usage:
39692  *    browser().navigateTo(url) Loads the url into the frame
39693  *    browser().navigateTo(url, fn) where fn(url) is called and returns the URL to navigate to
39694  *    browser().reload() refresh the page (reload the same URL)
39695  *    browser().window.href() window.location.href
39696  *    browser().window.path() window.location.pathname
39697  *    browser().window.search() window.location.search
39698  *    browser().window.hash() window.location.hash without # prefix
39699  *    browser().location().url() see ng.$location#url
39700  *    browser().location().path() see ng.$location#path
39701  *    browser().location().search() see ng.$location#search
39702  *    browser().location().hash() see ng.$location#hash
39703  */
39704 angular.scenario.dsl('browser', function() {
39705   var chain = {};
39706
39707   chain.navigateTo = function(url, delegate) {
39708     var application = this.application;
39709     return this.addFuture("browser navigate to '" + url + "'", function(done) {
39710       if (delegate) {
39711         url = delegate.call(this, url);
39712       }
39713       application.navigateTo(url, function() {
39714         done(null, url);
39715       }, done);
39716     });
39717   };
39718
39719   chain.reload = function() {
39720     var application = this.application;
39721     return this.addFutureAction('browser reload', function($window, $document, done) {
39722       var href = $window.location.href;
39723       application.navigateTo(href, function() {
39724         done(null, href);
39725       }, done);
39726     });
39727   };
39728
39729   chain.window = function() {
39730     var api = {};
39731
39732     api.href = function() {
39733       return this.addFutureAction('window.location.href', function($window, $document, done) {
39734         done(null, $window.location.href);
39735       });
39736     };
39737
39738     api.path = function() {
39739       return this.addFutureAction('window.location.path', function($window, $document, done) {
39740         done(null, $window.location.pathname);
39741       });
39742     };
39743
39744     api.search = function() {
39745       return this.addFutureAction('window.location.search', function($window, $document, done) {
39746         done(null, $window.location.search);
39747       });
39748     };
39749
39750     api.hash = function() {
39751       return this.addFutureAction('window.location.hash', function($window, $document, done) {
39752         done(null, $window.location.hash.replace('#', ''));
39753       });
39754     };
39755
39756     return api;
39757   };
39758
39759   chain.location = function() {
39760     var api = {};
39761
39762     api.url = function() {
39763       return this.addFutureAction('$location.url()', function($window, $document, done) {
39764         done(null, $document.injector().get('$location').url());
39765       });
39766     };
39767
39768     api.path = function() {
39769       return this.addFutureAction('$location.path()', function($window, $document, done) {
39770         done(null, $document.injector().get('$location').path());
39771       });
39772     };
39773
39774     api.search = function() {
39775       return this.addFutureAction('$location.search()', function($window, $document, done) {
39776         done(null, $document.injector().get('$location').search());
39777       });
39778     };
39779
39780     api.hash = function() {
39781       return this.addFutureAction('$location.hash()', function($window, $document, done) {
39782         done(null, $document.injector().get('$location').hash());
39783       });
39784     };
39785
39786     return api;
39787   };
39788
39789   return function() {
39790     return chain;
39791   };
39792 });
39793
39794 /**
39795  * Usage:
39796  *    expect(future).{matcher} where matcher is one of the matchers defined
39797  *    with angular.scenario.matcher
39798  *
39799  * ex. expect(binding("name")).toEqual("Elliott")
39800  */
39801 angular.scenario.dsl('expect', function() {
39802   var chain = angular.extend({}, angular.scenario.matcher);
39803
39804   chain.not = function() {
39805     this.inverse = true;
39806     return chain;
39807   };
39808
39809   return function(future) {
39810     this.future = future;
39811     return chain;
39812   };
39813 });
39814
39815 /**
39816  * Usage:
39817  *    using(selector, label) scopes the next DSL element selection
39818  *
39819  * ex.
39820  *   using('#foo', "'Foo' text field").input('bar')
39821  */
39822 angular.scenario.dsl('using', function() {
39823   return function(selector, label) {
39824     this.selector = _jQuery.trim((this.selector || '') + ' ' + selector);
39825     if (angular.isString(label) && label.length) {
39826       this.label = label + ' ( ' + this.selector + ' )';
39827     } else {
39828       this.label = this.selector;
39829     }
39830     return this.dsl;
39831   };
39832 });
39833
39834 /**
39835  * Usage:
39836  *    binding(name) returns the value of the first matching binding
39837  */
39838 angular.scenario.dsl('binding', function() {
39839   return function(name) {
39840     return this.addFutureAction("select binding '" + name + "'",
39841       function($window, $document, done) {
39842         var values = $document.elements().bindings($window.angular.element, name);
39843         if (!values.length) {
39844           return done("Binding selector '" + name + "' did not match.");
39845         }
39846         done(null, values[0]);
39847     });
39848   };
39849 });
39850
39851 /**
39852  * Usage:
39853  *    input(name).enter(value) enters value in input with specified name
39854  *    input(name).check() checks checkbox
39855  *    input(name).select(value) selects the radio button with specified name/value
39856  *    input(name).val() returns the value of the input.
39857  */
39858 angular.scenario.dsl('input', function() {
39859   var chain = {};
39860   var supportInputEvent = 'oninput' in document.createElement('div') && !(msie && msie <= 11);
39861
39862   chain.enter = function(value, event) {
39863     return this.addFutureAction("input '" + this.name + "' enter '" + value + "'",
39864       function($window, $document, done) {
39865         var input = $document.elements('[ng\\:model="$1"]', this.name).filter(':input');
39866         input.val(value);
39867         input.trigger(event || (supportInputEvent ? 'input' : 'change'));
39868         done();
39869     });
39870   };
39871
39872   chain.check = function() {
39873     return this.addFutureAction("checkbox '" + this.name + "' toggle",
39874       function($window, $document, done) {
39875         var input = $document.elements('[ng\\:model="$1"]', this.name).filter(':checkbox');
39876         input.trigger('click');
39877         done();
39878     });
39879   };
39880
39881   chain.select = function(value) {
39882     return this.addFutureAction("radio button '" + this.name + "' toggle '" + value + "'",
39883       function($window, $document, done) {
39884         var input = $document.
39885           elements('[ng\\:model="$1"][value="$2"]', this.name, value).filter(':radio');
39886         input.trigger('click');
39887         done();
39888     });
39889   };
39890
39891   chain.val = function() {
39892     return this.addFutureAction("return input val", function($window, $document, done) {
39893       var input = $document.elements('[ng\\:model="$1"]', this.name).filter(':input');
39894       done(null,input.val());
39895     });
39896   };
39897
39898   return function(name) {
39899     this.name = name;
39900     return chain;
39901   };
39902 });
39903
39904
39905 /**
39906  * Usage:
39907  *    repeater('#products table', 'Product List').count() number of rows
39908  *    repeater('#products table', 'Product List').row(1) all bindings in row as an array
39909  *    repeater('#products table', 'Product List').column('product.name') all values across all rows
39910  *    in an array
39911  */
39912 angular.scenario.dsl('repeater', function() {
39913   var chain = {};
39914
39915   chain.count = function() {
39916     return this.addFutureAction("repeater '" + this.label + "' count",
39917       function($window, $document, done) {
39918         try {
39919           done(null, $document.elements().length);
39920         } catch (e) {
39921           done(null, 0);
39922         }
39923     });
39924   };
39925
39926   chain.column = function(binding) {
39927     return this.addFutureAction("repeater '" + this.label + "' column '" + binding + "'",
39928       function($window, $document, done) {
39929         done(null, $document.elements().bindings($window.angular.element, binding));
39930     });
39931   };
39932
39933   chain.row = function(index) {
39934     return this.addFutureAction("repeater '" + this.label + "' row '" + index + "'",
39935       function($window, $document, done) {
39936         var matches = $document.elements().slice(index, index + 1);
39937         if (!matches.length) {
39938           return done('row ' + index + ' out of bounds');
39939         }
39940         done(null, matches.bindings($window.angular.element));
39941     });
39942   };
39943
39944   return function(selector, label) {
39945     this.dsl.using(selector, label);
39946     return chain;
39947   };
39948 });
39949
39950 /**
39951  * Usage:
39952  *    select(name).option('value') select one option
39953  *    select(name).options('value1', 'value2', ...) select options from a multi select
39954  */
39955 angular.scenario.dsl('select', function() {
39956   var chain = {};
39957
39958   chain.option = function(value) {
39959     return this.addFutureAction("select '" + this.name + "' option '" + value + "'",
39960       function($window, $document, done) {
39961         var select = $document.elements('select[ng\\:model="$1"]', this.name);
39962         var option = select.find('option[value="' + value + '"]');
39963         if (option.length) {
39964           select.val(value);
39965         } else {
39966           option = select.find('option').filter(function() {
39967             return _jQuery(this).text() === value;
39968           });
39969           if (!option.length) {
39970             option = select.find('option:contains("' + value + '")');
39971           }
39972           if (option.length) {
39973             select.val(option.val());
39974           } else {
39975               return done("option '" + value + "' not found");
39976           }
39977         }
39978         select.trigger('change');
39979         done();
39980     });
39981   };
39982
39983   chain.options = function() {
39984     var values = arguments;
39985     return this.addFutureAction("select '" + this.name + "' options '" + values + "'",
39986       function($window, $document, done) {
39987         var select = $document.elements('select[multiple][ng\\:model="$1"]', this.name);
39988         select.val(values);
39989         select.trigger('change');
39990         done();
39991     });
39992   };
39993
39994   return function(name) {
39995     this.name = name;
39996     return chain;
39997   };
39998 });
39999
40000 /**
40001  * Usage:
40002  *    element(selector, label).count() get the number of elements that match selector
40003  *    element(selector, label).click() clicks an element
40004  *    element(selector, label).mouseover() mouseover an element
40005  *    element(selector, label).mousedown() mousedown an element
40006  *    element(selector, label).mouseup() mouseup an element
40007  *    element(selector, label).query(fn) executes fn(selectedElements, done)
40008  *    element(selector, label).{method}() gets the value (as defined by jQuery, ex. val)
40009  *    element(selector, label).{method}(value) sets the value (as defined by jQuery, ex. val)
40010  *    element(selector, label).{method}(key) gets the value (as defined by jQuery, ex. attr)
40011  *    element(selector, label).{method}(key, value) sets the value (as defined by jQuery, ex. attr)
40012  */
40013 angular.scenario.dsl('element', function() {
40014   var KEY_VALUE_METHODS = ['attr', 'css', 'prop'];
40015   var VALUE_METHODS = [
40016     'val', 'text', 'html', 'height', 'innerHeight', 'outerHeight', 'width',
40017     'innerWidth', 'outerWidth', 'position', 'scrollLeft', 'scrollTop', 'offset'
40018   ];
40019   var chain = {};
40020
40021   chain.count = function() {
40022     return this.addFutureAction("element '" + this.label + "' count",
40023       function($window, $document, done) {
40024         try {
40025           done(null, $document.elements().length);
40026         } catch (e) {
40027           done(null, 0);
40028         }
40029     });
40030   };
40031
40032   chain.click = function() {
40033     return this.addFutureAction("element '" + this.label + "' click",
40034       function($window, $document, done) {
40035         var elements = $document.elements();
40036         var href = elements.attr('href');
40037         var eventProcessDefault = elements.trigger('click')[0];
40038
40039         if (href && elements[0].nodeName.toLowerCase() === 'a' && eventProcessDefault) {
40040           this.application.navigateTo(href, function() {
40041             done();
40042           }, done);
40043         } else {
40044           done();
40045         }
40046     });
40047   };
40048
40049   chain.dblclick = function() {
40050     return this.addFutureAction("element '" + this.label + "' dblclick",
40051       function($window, $document, done) {
40052         var elements = $document.elements();
40053         var href = elements.attr('href');
40054         var eventProcessDefault = elements.trigger('dblclick')[0];
40055
40056         if (href && elements[0].nodeName.toLowerCase() === 'a' && eventProcessDefault) {
40057           this.application.navigateTo(href, function() {
40058             done();
40059           }, done);
40060         } else {
40061           done();
40062         }
40063     });
40064   };
40065
40066   chain.mouseover = function() {
40067     return this.addFutureAction("element '" + this.label + "' mouseover",
40068       function($window, $document, done) {
40069         var elements = $document.elements();
40070         elements.trigger('mouseover');
40071         done();
40072     });
40073   };
40074
40075   chain.mousedown = function() {
40076       return this.addFutureAction("element '" + this.label + "' mousedown",
40077         function($window, $document, done) {
40078           var elements = $document.elements();
40079           elements.trigger('mousedown');
40080           done();
40081       });
40082     };
40083
40084   chain.mouseup = function() {
40085       return this.addFutureAction("element '" + this.label + "' mouseup",
40086         function($window, $document, done) {
40087           var elements = $document.elements();
40088           elements.trigger('mouseup');
40089           done();
40090       });
40091     };
40092
40093   chain.query = function(fn) {
40094     return this.addFutureAction('element ' + this.label + ' custom query',
40095       function($window, $document, done) {
40096         fn.call(this, $document.elements(), done);
40097     });
40098   };
40099
40100   angular.forEach(KEY_VALUE_METHODS, function(methodName) {
40101     chain[methodName] = function(name, value) {
40102       var args = arguments,
40103           futureName = (args.length == 1)
40104               ? "element '" + this.label + "' get " + methodName + " '" + name + "'"
40105               : "element '" + this.label + "' set " + methodName + " '" + name + "' to " + "'" +
40106                 value + "'";
40107
40108       return this.addFutureAction(futureName, function($window, $document, done) {
40109         var element = $document.elements();
40110         done(null, element[methodName].apply(element, args));
40111       });
40112     };
40113   });
40114
40115   angular.forEach(VALUE_METHODS, function(methodName) {
40116     chain[methodName] = function(value) {
40117       var args = arguments,
40118           futureName = (args.length === 0)
40119               ? "element '" + this.label + "' " + methodName
40120               : "element '" + this.label + "' set " + methodName + " to '" + value + "'";
40121
40122       return this.addFutureAction(futureName, function($window, $document, done) {
40123         var element = $document.elements();
40124         done(null, element[methodName].apply(element, args));
40125       });
40126     };
40127   });
40128
40129   return function(selector, label) {
40130     this.dsl.using(selector, label);
40131     return chain;
40132   };
40133 });
40134
40135 /**
40136  * Matchers for implementing specs. Follows the Jasmine spec conventions.
40137  */
40138
40139 angular.scenario.matcher('toEqual', function(expected) {
40140   return angular.equals(this.actual, expected);
40141 });
40142
40143 angular.scenario.matcher('toBe', function(expected) {
40144   return this.actual === expected;
40145 });
40146
40147 angular.scenario.matcher('toBeDefined', function() {
40148   return angular.isDefined(this.actual);
40149 });
40150
40151 angular.scenario.matcher('toBeTruthy', function() {
40152   return this.actual;
40153 });
40154
40155 angular.scenario.matcher('toBeFalsy', function() {
40156   return !this.actual;
40157 });
40158
40159 angular.scenario.matcher('toMatch', function(expected) {
40160   return new RegExp(expected).test(this.actual);
40161 });
40162
40163 angular.scenario.matcher('toBeNull', function() {
40164   return this.actual === null;
40165 });
40166
40167 angular.scenario.matcher('toContain', function(expected) {
40168   return includes(this.actual, expected);
40169 });
40170
40171 angular.scenario.matcher('toBeLessThan', function(expected) {
40172   return this.actual < expected;
40173 });
40174
40175 angular.scenario.matcher('toBeGreaterThan', function(expected) {
40176   return this.actual > expected;
40177 });
40178
40179 /**
40180  * User Interface for the Scenario Runner.
40181  *
40182  * TODO(esprehn): This should be refactored now that ObjectModel exists
40183  *  to use angular bindings for the UI.
40184  */
40185 angular.scenario.output('html', function(context, runner, model) {
40186   var specUiMap = {},
40187       lastStepUiMap = {};
40188
40189   context.append(
40190     '<div id="header">' +
40191     '  <h1><span class="angular">AngularJS</span>: Scenario Test Runner</h1>' +
40192     '  <ul id="status-legend" class="status-display">' +
40193     '    <li class="status-error">0 Errors</li>' +
40194     '    <li class="status-failure">0 Failures</li>' +
40195     '    <li class="status-success">0 Passed</li>' +
40196     '  </ul>' +
40197     '</div>' +
40198     '<div id="specs">' +
40199     '  <div class="test-children"></div>' +
40200     '</div>'
40201   );
40202
40203   runner.on('InteractivePause', function(spec) {
40204     var ui = lastStepUiMap[spec.id];
40205     ui.find('.test-title').
40206       html('paused... <a href="javascript:resume()">resume</a> when ready.');
40207   });
40208
40209   runner.on('SpecBegin', function(spec) {
40210     var ui = findContext(spec);
40211     ui.find('> .tests').append(
40212       '<li class="status-pending test-it"></li>'
40213     );
40214     ui = ui.find('> .tests li:last');
40215     ui.append(
40216       '<div class="test-info">' +
40217       '  <p class="test-title">' +
40218       '    <span class="timer-result"></span>' +
40219       '    <span class="test-name"></span>' +
40220       '  </p>' +
40221       '</div>' +
40222       '<div class="scrollpane">' +
40223       '  <ol class="test-actions"></ol>' +
40224       '</div>'
40225     );
40226     ui.find('> .test-info .test-name').text(spec.name);
40227     ui.find('> .test-info').click(function() {
40228       var scrollpane = ui.find('> .scrollpane');
40229       var actions = scrollpane.find('> .test-actions');
40230       var name = context.find('> .test-info .test-name');
40231       if (actions.find(':visible').length) {
40232         actions.hide();
40233         name.removeClass('open').addClass('closed');
40234       } else {
40235         actions.show();
40236         scrollpane.attr('scrollTop', scrollpane.attr('scrollHeight'));
40237         name.removeClass('closed').addClass('open');
40238       }
40239     });
40240
40241     specUiMap[spec.id] = ui;
40242   });
40243
40244   runner.on('SpecError', function(spec, error) {
40245     var ui = specUiMap[spec.id];
40246     ui.append('<pre></pre>');
40247     ui.find('> pre').text(formatException(error));
40248   });
40249
40250   runner.on('SpecEnd', function(spec) {
40251     var ui = specUiMap[spec.id];
40252     spec = model.getSpec(spec.id);
40253     ui.removeClass('status-pending');
40254     ui.addClass('status-' + spec.status);
40255     ui.find("> .test-info .timer-result").text(spec.duration + "ms");
40256     if (spec.status === 'success') {
40257       ui.find('> .test-info .test-name').addClass('closed');
40258       ui.find('> .scrollpane .test-actions').hide();
40259     }
40260     updateTotals(spec.status);
40261   });
40262
40263   runner.on('StepBegin', function(spec, step) {
40264     var ui = specUiMap[spec.id];
40265     spec = model.getSpec(spec.id);
40266     step = spec.getLastStep();
40267     ui.find('> .scrollpane .test-actions').append('<li class="status-pending"></li>');
40268     var stepUi = lastStepUiMap[spec.id] = ui.find('> .scrollpane .test-actions li:last');
40269     stepUi.append(
40270       '<div class="timer-result"></div>' +
40271       '<div class="test-title"></div>'
40272     );
40273     stepUi.find('> .test-title').text(step.name);
40274     var scrollpane = stepUi.parents('.scrollpane');
40275     scrollpane.attr('scrollTop', scrollpane.attr('scrollHeight'));
40276   });
40277
40278   runner.on('StepFailure', function(spec, step, error) {
40279     var ui = lastStepUiMap[spec.id];
40280     addError(ui, step.line, error);
40281   });
40282
40283   runner.on('StepError', function(spec, step, error) {
40284     var ui = lastStepUiMap[spec.id];
40285     addError(ui, step.line, error);
40286   });
40287
40288   runner.on('StepEnd', function(spec, step) {
40289     var stepUi = lastStepUiMap[spec.id];
40290     spec = model.getSpec(spec.id);
40291     step = spec.getLastStep();
40292     stepUi.find('.timer-result').text(step.duration + 'ms');
40293     stepUi.removeClass('status-pending');
40294     stepUi.addClass('status-' + step.status);
40295     var scrollpane = specUiMap[spec.id].find('> .scrollpane');
40296     scrollpane.attr('scrollTop', scrollpane.attr('scrollHeight'));
40297   });
40298
40299   /**
40300    * Finds the context of a spec block defined by the passed definition.
40301    *
40302    * @param {Object} The definition created by the Describe object.
40303    */
40304   function findContext(spec) {
40305     var currentContext = context.find('#specs');
40306     angular.forEach(model.getDefinitionPath(spec), function(defn) {
40307       var id = 'describe-' + defn.id;
40308       if (!context.find('#' + id).length) {
40309         currentContext.find('> .test-children').append(
40310           '<div class="test-describe" id="' + id + '">' +
40311           '  <h2></h2>' +
40312           '  <div class="test-children"></div>' +
40313           '  <ul class="tests"></ul>' +
40314           '</div>'
40315         );
40316         context.find('#' + id).find('> h2').text('describe: ' + defn.name);
40317       }
40318       currentContext = context.find('#' + id);
40319     });
40320     return context.find('#describe-' + spec.definition.id);
40321   }
40322
40323   /**
40324    * Updates the test counter for the status.
40325    *
40326    * @param {string} the status.
40327    */
40328   function updateTotals(status) {
40329     var legend = context.find('#status-legend .status-' + status);
40330     var parts = legend.text().split(' ');
40331     var value = (parts[0] * 1) + 1;
40332     legend.text(value + ' ' + parts[1]);
40333   }
40334
40335   /**
40336    * Add an error to a step.
40337    *
40338    * @param {Object} The JQuery wrapped context
40339    * @param {function()} fn() that should return the file/line number of the error
40340    * @param {Object} the error.
40341    */
40342   function addError(context, line, error) {
40343     context.find('.test-title').append('<pre></pre>');
40344     var message = _jQuery.trim(line() + '\n\n' + formatException(error));
40345     context.find('.test-title pre:last').text(message);
40346   }
40347 });
40348
40349 /**
40350  * Generates JSON output into a context.
40351  */
40352 angular.scenario.output('json', function(context, runner, model) {
40353   model.on('RunnerEnd', function() {
40354     context.text(angular.toJson(model.value));
40355   });
40356 });
40357
40358 /**
40359  * Generates XML output into a context.
40360  */
40361 angular.scenario.output('xml', function(context, runner, model) {
40362   var $ = function(args) {return new context.init(args);};
40363   model.on('RunnerEnd', function() {
40364     var scenario = $('<scenario></scenario>');
40365     context.append(scenario);
40366     serializeXml(scenario, model.value);
40367   });
40368
40369   /**
40370    * Convert the tree into XML.
40371    *
40372    * @param {Object} context jQuery context to add the XML to.
40373    * @param {Object} tree node to serialize
40374    */
40375   function serializeXml(context, tree) {
40376      angular.forEach(tree.children, function(child) {
40377        var describeContext = $('<describe></describe>');
40378        describeContext.attr('id', child.id);
40379        describeContext.attr('name', child.name);
40380        context.append(describeContext);
40381        serializeXml(describeContext, child);
40382      });
40383      var its = $('<its></its>');
40384      context.append(its);
40385      angular.forEach(tree.specs, function(spec) {
40386        var it = $('<it></it>');
40387        it.attr('id', spec.id);
40388        it.attr('name', spec.name);
40389        it.attr('duration', spec.duration);
40390        it.attr('status', spec.status);
40391        its.append(it);
40392        angular.forEach(spec.steps, function(step) {
40393          var stepContext = $('<step></step>');
40394          stepContext.attr('name', step.name);
40395          stepContext.attr('duration', step.duration);
40396          stepContext.attr('status', step.status);
40397          it.append(stepContext);
40398          if (step.error) {
40399            var error = $('<error></error>');
40400            stepContext.append(error);
40401            error.text(formatException(step.error));
40402          }
40403        });
40404      });
40405    }
40406 });
40407
40408 /**
40409  * Creates a global value $result with the result of the runner.
40410  */
40411 angular.scenario.output('object', function(context, runner, model) {
40412   runner.$window.$result = model.value;
40413 });
40414
40415 bindJQuery();
40416 publishExternalAPI(angular);
40417
40418 var $runner = new angular.scenario.Runner(window),
40419     scripts = document.getElementsByTagName('script'),
40420     script = scripts[scripts.length - 1],
40421     config = {};
40422
40423 angular.forEach(script.attributes, function(attr) {
40424   var match = attr.name.match(/ng[:\-](.*)/);
40425   if (match) {
40426     config[match[1]] = attr.value || true;
40427   }
40428 });
40429
40430 if (config.autotest) {
40431   JQLite(document).ready(function() {
40432     angular.scenario.setUpAndRun(config);
40433   });
40434 }
40435 })(window, document);
40436
40437
40438 !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>');
40439 !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>');