PageSourceSearch

https://groundupmusic.net/dist/vendor.js

js groundupmusic.net collected 2026-10-02 12:10:03 UTC 1,587,067 bytes, 46,064 lines download raw bytes

vendor: 12,689 bytes, lines 1-531
1/*!
2 * jQuery JavaScript Library v3.2.1
3 * https://jquery.com/
4 *
5 * Includes Sizzle.js
6 * https://sizzlejs.com/
7 *
8 * Copyright JS Foundation and other contributors
9 * Released under the MIT license
10 * https://jquery.org/license
11 *
12 * Date: 2017-03-20T18:59Z
13 */
14( function( global, factory ) {
15
16	"use strict";
17
18	if ( typeof module === "object" && typeof module.exports === "object" ) {
19
20		// For CommonJS and CommonJS-like environments where a proper `window`
21		// is present, execute the factory and get jQuery.
22		// For environments that do not have a `window` with a `document`
23		// (such as Node.js), expose a factory as module.exports.
24		// This accentuates the need for the creation of a real `window`.
25		// e.g. var jQuery = require("jquery")(window);
26		// See ticket #14549 for more info.
27		module.exports = global.document ?
28			factory( global, true ) :
29			function( w ) {
30				if ( !w.document ) {
31					throw new Error( "jQuery requires a window with a document" );
32				}
33				return factory( w );
34			};
35	} else {
36		factory( global );
37	}
38
39// Pass this if window is not defined yet
40} )( typeof window !== "undefined" ? window : this, function( window, noGlobal ) {
41
42// Edge <= 12 - 13+, Firefox <=18 - 45+, IE 10 - 11, Safari 5.1 - 9+, iOS 6 - 9.1
43// throw exceptions when non-strict code (e.g., ASP.NET 4.5) accesses strict mode
44// arguments.callee.caller (trac-13335). But as of jQuery 3.0 (2016), strict mode should be common
45// enough that all such attempts are guarded in a try block.
46"use strict";
47
48var arr = [];
49
50var document = window.document;
51
52var getProto = Object.getPrototypeOf;
53
54var slice = arr.slice;
55
56var concat = arr.concat;
57
58var push = arr.push;
59
60var indexOf = arr.indexOf;
61
62var class2type = {};
63
64var toString = class2type.toString;
65
66var hasOwn = class2type.hasOwnProperty;
67
68var fnToString = hasOwn.toString;
69
70var ObjectFunctionString = fnToString.call( Object );
71
72var support = {};
73
74
75
76	function DOMEval( code, doc ) {
77		doc = doc || document;
78
79		var script = doc.createElement( "script" );
80
81		script.text = code;
82		doc.head.appendChild( script ).parentNode.removeChild( script );
83	}
84/* global Symbol */
85// Defining this global in .eslintrc.json would create a danger of using the global
86// unguarded in another place, it seems safer to define global only for this module
87
88
89
90var
91	version = "3.2.1",
92
93	// Define a local copy of jQuery
94	jQuery = function( selector, context ) {
95
96		// The jQuery object is actually just the init constructor 'enhanced'
97		// Need init if jQuery is called (just allow error to be thrown if not included)
98		return new jQuery.fn.init( selector, context );
99	},
100
101	// Support: Android <=4.0 only
102	// Make sure we trim BOM and NBSP
103	rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,
104
105	// Matches dashed string for camelizing
106	rmsPrefix = /^-ms-/,
107	rdashAlpha = /-([a-z])/g,
108
109	// Used by jQuery.camelCase as callback to replace()
110	fcamelCase = function( all, letter ) {
111		return letter.toUpperCase();
112	};
113
114jQuery.fn = jQuery.prototype = {
115
116	// The current version of jQuery being used
117	jquery: version,
118
119	constructor: jQuery,
120
121	// The default length of a jQuery object is 0
122	length: 0,
123
124	toArray: function() {
125		return slice.call( this );
126	},
127
128	// Get the Nth element in the matched element set OR
129	// Get the whole matched element set as a clean array
130	get: function( num ) {
131
132		// Return all the elements in a clean array
133		if ( num == null ) {
134			return slice.call( this );
135		}
136
137		// Return just the one element from the set
138		return num < 0 ? this[ num + this.length ] : this[ num ];
139	},
140
141	// Take an array of elements and push it onto the stack
142	// (returning the new matched element set)
143	pushStack: function( elems ) {
144
145		// Build a new jQuery matched element set
146		var ret = jQuery.merge( this.constructor(), elems );
147
148		// Add the old object onto the stack (as a reference)
149		ret.prevObject = this;
150
151		// Return the newly-formed element set
152		return ret;
153	},
154
155	// Execute a callback for every element in the matched set.
156	each: function( callback ) {
157		return jQuery.each( this, callback );
158	},
159
160	map: function( callback ) {
161		return this.pushStack( jQuery.map( this, function( elem, i ) {
162			return callback.call( elem, i, elem );
163		} ) );
164	},
165
166	slice: function() {
167		return this.pushStack( slice.apply( this, arguments ) );
168	},
169
170	first: function() {
171		return this.eq( 0 );
172	},
173
174	last: function() {
175		return this.eq( -1 );
176	},
177
178	eq: function( i ) {
179		var len = this.length,
180			j = +i + ( i < 0 ? len : 0 );
181		return this.pushStack( j >= 0 && j < len ? [ this[ j ] ] : [] );
182	},
183
184	end: function() {
185		return this.prevObject || this.constructor();
186	},
187
188	// For internal use only.
189	// Behaves like an Array's method, not like a jQuery method.
190	push: push,
191	sort: arr.sort,
192	splice: arr.splice
193};
194
195jQuery.extend = jQuery.fn.extend = function() {
196	var options, name, src, copy, copyIsArray, clone,
197		target = arguments[ 0 ] || {},
198		i = 1,
199		length = arguments.length,
200		deep = false;
201
202	// Handle a deep copy situation
203	if ( typeof target === "boolean" ) {
204		deep = target;
205
206		// Skip the boolean and the target
207		target = arguments[ i ] || {};
208		i++;
209	}
210
211	// Handle case when target is a string or something (possible in deep copy)
212	if ( typeof target !== "object" && !jQuery.isFunction( target ) ) {
213		target = {};
214	}
215
216	// Extend jQuery itself if only one argument is passed
217	if ( i === length ) {
218		target = this;
219		i--;
220	}
221
222	for ( ; i < length; i++ ) {
223
224		// Only deal with non-null/undefined values
225		if ( ( options = arguments[ i ] ) != null ) {
226
227			// Extend the base object
228			for ( name in options ) {
229				src = target[ name ];
230				copy = options[ name ];
231
232				// Prevent never-ending loop
233				if ( target === copy ) {
234					continue;
235				}
236
237				// Recurse if we're merging plain objects or arrays
238				if ( deep && copy && ( jQuery.isPlainObject( copy ) ||
239					( copyIsArray = Array.isArray( copy ) ) ) ) {
240
241					if ( copyIsArray ) {
242						copyIsArray = false;
243						clone = src && Array.isArray( src ) ? src : [];
244
245					} else {
246						clone = src && jQuery.isPlainObject( src ) ? src : {};
247					}
248
249					// Never move original objects, clone them
250					target[ name ] = jQuery.extend( deep, clone, copy );
251
252				// Don't bring in undefined values
253				} else if ( copy !== undefined ) {
254					target[ name ] = copy;
255				}
256			}
257		}
258	}
259
260	// Return the modified object
261	return target;
262};
263
264jQuery.extend( {
265
266	// Unique for each copy of jQuery on the page
267	expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ),
268
269	// Assume jQuery is ready without the ready module
270	isReady: true,
271
272	error: function( msg ) {
273		throw new Error( msg );
274	},
275
276	noop: function() {},
277
278	isFunction: function( obj ) {
279		return jQuery.type( obj ) === "function";
280	},
281
282	isWindow: function( obj ) {
283		return obj != null && obj === obj.window;
284	},
285
286	isNumeric: function( obj ) {
287
288		// As of jQuery 3.0, isNumeric is limited to
289		// strings and numbers (primitives or objects)
290		// that can be coerced to finite numbers (gh-2662)
291		var type = jQuery.type( obj );
292		return ( type === "number" || type === "string" ) &&
293
294			// parseFloat NaNs numeric-cast false positives ("")
295			// ...but misinterprets leading-number strings, particularly hex literals ("0x...")
296			// subtraction forces infinities to NaN
297			!isNaN( obj - parseFloat( obj ) );
298	},
299
300	isPlainObject: function( obj ) {
301		var proto, Ctor;
302
303		// Detect obvious negatives
304		// Use toString instead of jQuery.type to catch host objects
305		if ( !obj || toString.call( obj ) !== "[object Object]" ) {
306			return false;
307		}
308
309		proto = getProto( obj );
310
311		// Objects with no prototype (e.g., `Object.create( null )`) are plain
312		if ( !proto ) {
313			return true;
314		}
315
316		// Objects with prototype are plain iff they were constructed by a global Object function
317		Ctor = hasOwn.call( proto, "constructor" ) && proto.constructor;
318		return typeof Ctor === "function" && fnToString.call( Ctor ) === ObjectFunctionString;
319	},
320
321	isEmptyObject: function( obj ) {
322
323		/* eslint-disable no-unused-vars */
324		// See https://github.com/eslint/eslint/issues/6125
325		var name;
326
327		for ( name in obj ) {
328			return false;
329		}
330		return true;
331	},
332
333	type: function( obj ) {
334		if ( obj == null ) {
335			return obj + "";
336		}
337
338		// Support: Android <=2.3 only (functionish RegExp)
339		return typeof obj === "object" || typeof obj === "function" ?
340			class2type[ toString.call( obj ) ] || "object" :
341			typeof obj;
342	},
343
344	// Evaluates a script in a global context
345	globalEval: function( code ) {
346		DOMEval( code );
347	},
348
349	// Convert dashed to camelCase; used by the css and data modules
350	// Support: IE <=9 - 11, Edge 12 - 13
351	// Microsoft forgot to hump their vendor prefix (#9572)
352	camelCase: function( string ) {
353		return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase );
354	},
355
356	each: function( obj, callback ) {
357		var length, i = 0;
358
359		if ( isArrayLike( obj ) ) {
360			length = obj.length;
361			for ( ; i < length; i++ ) {
362				if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) {
363					break;
364				}
365			}
366		} else {
367			for ( i in obj ) {
368				if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) {
369					break;
370				}
371			}
372		}
373
374		return obj;
375	},
376
377	// Support: Android <=4.0 only
378	trim: function( text ) {
379		return text == null ?
380			"" :
381			( text + "" ).replace( rtrim, "" );
382	},
383
384	// results is for internal usage only
385	makeArray: function( arr, results ) {
386		var ret = results || [];
387
388		if ( arr != null ) {
389			if ( isArrayLike( Object( arr ) ) ) {
390				jQuery.merge( ret,
391					typeof arr === "string" ?
392					[ arr ] : arr
393				);
394			} else {
395				push.call( ret, arr );
396			}
397		}
398
399		return ret;
400	},
401
402	inArray: function( elem, arr, i ) {
403		return arr == null ? -1 : indexOf.call( arr, elem, i );
404	},
405
406	// Support: Android <=4.0 only, PhantomJS 1 only
407	// push.apply(_, arraylike) throws on ancient WebKit
408	merge: function( first, second ) {
409		var len = +second.length,
410			j = 0,
411			i = first.length;
412
413		for ( ; j < len; j++ ) {
414			first[ i++ ] = second[ j ];
415		}
416
417		first.length = i;
418
419		return first;
420	},
421
422	grep: function( elems, callback, invert ) {
423		var callbackInverse,
424			matches = [],
425			i = 0,
426			length = elems.length,
427			callbackExpect = !invert;
428
429		// Go through the array, only saving the items
430		// that pass the validator function
431		for ( ; i < length; i++ ) {
432			callbackInverse = !callback( elems[ i ], i );
433			if ( callbackInverse !== callbackExpect ) {
434				matches.push( elems[ i ] );
435			}
436		}
437
438		return matches;
439	},
440
441	// arg is for internal usage only
442	map: function( elems, callback, arg ) {
443		var length, value,
444			i = 0,
445			ret = [];
446
447		// Go through the array, translating each of the items to their new values
448		if ( isArrayLike( elems ) ) {
449			length = elems.length;
450			for ( ; i < length; i++ ) {
451				value = callback( elems[ i ], i, arg );
452
453				if ( value != null ) {
454					ret.push( value );
455				}
456			}
457
458		// Go through every key on the object,
459		} else {
460			for ( i in elems ) {
461				value = callback( elems[ i ], i, arg );
462
463				if ( value != null ) {
464					ret.push( value );
465				}
466			}
467		}
468
469		// Flatten any nested arrays
470		return concat.apply( [], ret );
471	},
472
473	// A global GUID counter for objects
474	guid: 1,
475
476	// Bind a function to a context, optionally partially applying any
477	// arguments.
478	proxy: function( fn, context ) {
479		var tmp, args, proxy;
480
481		if ( typeof context === "string" ) {
482			tmp = fn[ context ];
483			context = fn;
484			fn = tmp;
485		}
486
487		// Quick check to determine if target is callable, in the spec
488		// this throws a TypeError, but we will just return undefined.
489		if ( !jQuery.isFunction( fn ) ) {
490			return undefined;
491		}
492
493		// Simulated bind
494		args = slice.call( arguments, 2 );
495		proxy = function() {
496			return fn.apply( context || this, args.concat( slice.call( arguments ) ) );
497		};
498
499		// Set the guid of unique handler to the same of original handler, so it can be removed
500		proxy.guid = fn.guid = fn.guid || jQuery.guid++;
501
502		return proxy;
503	},
504
505	now: Date.now,
506
507	// jQuery.support is not used in Core but other projects attach their
508	// properties to it so it needs to exist.
509	support: support
510} );
511
512if ( typeof Symbol === "function" ) {
513	jQuery.fn[ Symbol.iterator ] = arr[ Symbol.iterator ];
514}
515
516// Populate the class2type map
517jQuery.each( "Boolean Number String Function Array Date RegExp Object Error Symbol".split( " " ),
518function( i, name ) {
519	class2type[ "[object " + name + "]" ] = name.toLowerCase();
520} );
521
522function isArrayLike( obj ) {
523
524	// Support: real iOS 8.2 only (not reproducible in simulator)
525	// `in` check used to prevent JIT error (gh-2145)
526	// hasOwn isn't used here due to false negatives
527	// regarding Nodelist length in IE
528	var length = !!obj && "length" in obj && obj.length,
529		type = jQuery.type( obj );
530
531	if ( type === "function" || jQuery.
vendor: 31,442 bytes, lines 531-1628
531isWindow( obj ) ) {
532		return false;
533	}
534
535	return type === "array" || length === 0 ||
536		typeof length === "number" && length > 0 && ( length - 1 ) in obj;
537}
538var Sizzle =
539/*!
540 * Sizzle CSS Selector Engine v2.3.3
541 * https://sizzlejs.com/
542 *
543 * Copyright jQuery Foundation and other contributors
544 * Released under the MIT license
545 * http://jquery.org/license
546 *
547 * Date: 2016-08-08
548 */
549(function( window ) {
550
551var i,
552	support,
553	Expr,
554	getText,
555	isXML,
556	tokenize,
557	compile,
558	select,
559	outermostContext,
560	sortInput,
561	hasDuplicate,
562
563	// Local document vars
564	setDocument,
565	document,
566	docElem,
567	documentIsHTML,
568	rbuggyQSA,
569	rbuggyMatches,
570	matches,
571	contains,
572
573	// Instance-specific data
574	expando = "sizzle" + 1 * new Date(),
575	preferredDoc = window.document,
576	dirruns = 0,
577	done = 0,
578	classCache = createCache(),
579	tokenCache = createCache(),
580	compilerCache = createCache(),
581	sortOrder = function( a, b ) {
582		if ( a === b ) {
583			hasDuplicate = true;
584		}
585		return 0;
586	},
587
588	// Instance methods
589	hasOwn = ({}).hasOwnProperty,
590	arr = [],
591	pop = arr.pop,
592	push_native = arr.push,
593	push = arr.push,
594	slice = arr.slice,
595	// Use a stripped-down indexOf as it's faster than native
596	// https://jsperf.com/thor-indexof-vs-for/5
597	indexOf = function( list, elem ) {
598		var i = 0,
599			len = list.length;
600		for ( ; i < len; i++ ) {
601			if ( list[i] === elem ) {
602				return i;
603			}
604		}
605		return -1;
606	},
607
608	booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",
609
610	// Regular expressions
611
612	// http://www.w3.org/TR/css3-selectors/#whitespace
613	whitespace = "[\\x20\\t\\r\\n\\f]",
614
615	// http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier
616	identifier = "(?:\\\\.|[\\w-]|[^\0-\\xa0])+",
617
618	// Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors
619	attributes = "\\[" + whitespace + "*(" + identifier + ")(?:" + whitespace +
620		// Operator (capture 2)
621		"*([*^$|!~]?=)" + whitespace +
622		// "Attribute values must be CSS identifiers [capture 5] or strings [capture 3 or capture 4]"
623		"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + whitespace +
624		"*\\]",
625
626	pseudos = ":(" + identifier + ")(?:\\((" +
627		// To reduce the number of selectors needing tokenize in the preFilter, prefer arguments:
628		// 1. quoted (capture 3; capture 4 or capture 5)
629		"('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" +
630		// 2. simple (capture 6)
631		"((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" +
632		// 3. anything else (capture 2)
633		".*" +
634		")\\)|)",
635
636	// Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter
637	rwhitespace = new RegExp( whitespace + "+", "g" ),
638	rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ),
639
640	rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ),
641	rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + "*" ),
642
643	rattributeQuotes = new RegExp( "=" + whitespace + "*([^\\]'\"]*?)" + whitespace + "*\\]", "g" ),
644
645	rpseudo = new RegExp( pseudos ),
646	ridentifier = new RegExp( "^" + identifier + "$" ),
647
648	matchExpr = {
649		"ID": new RegExp( "^#(" + identifier + ")" ),
650		"CLASS": new RegExp( "^\\.(" + identifier + ")" ),
651		"TAG": new RegExp( "^(" + identifier + "|[*])" ),
652		"ATTR": new RegExp( "^" + attributes ),
653		"PSEUDO": new RegExp( "^" + pseudos ),
654		"CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace +
655			"*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace +
656			"*(\\d+)|))" + whitespace + "*\\)|)", "i" ),
657		"bool": new RegExp( "^(?:" + booleans + ")$", "i" ),
658		// For use in libraries implementing .is()
659		// We use this for POS matching in `select`
660		"needsContext": new RegExp( "^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" +
661			whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" )
662	},
663
664	rinputs = /^(?:input|select|textarea|button)$/i,
665	rheader = /^h\d$/i,
666
667	rnative = /^[^{]+\{\s*\[native \w/,
668
669	// Easily-parseable/retrievable ID or TAG or CLASS selectors
670	rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,
671
672	rsibling = /[+~]/,
673
674	// CSS escapes
675	// http://www.w3.org/TR/CSS21/syndata.html#escaped-characters
676	runescape = new RegExp( "\\\\([\\da-f]{1,6}" + whitespace + "?|(" + whitespace + ")|.)", "ig" ),
677	funescape = function( _, escaped, escapedWhitespace ) {
678		var high = "0x" + escaped - 0x10000;
679		// NaN means non-codepoint
680		// Support: Firefox<24
681		// Workaround erroneous numeric interpretation of +"0x"
682		return high !== high || escapedWhitespace ?
683			escaped :
684			high < 0 ?
685				// BMP codepoint
686				String.fromCharCode( high + 0x10000 ) :
687				// Supplemental Plane codepoint (surrogate pair)
688				String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 );
689	},
690
691	// CSS string/identifier serialization
692	// https://drafts.csswg.org/cssom/#common-serializing-idioms
693	rcssescape = /([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,
694	fcssescape = function( ch, asCodePoint ) {
695		if ( asCodePoint ) {
696
697			// U+0000 NULL becomes U+FFFD REPLACEMENT CHARACTER
698			if ( ch === "\0" ) {
699				return "\uFFFD";
700			}
701
702			// Control characters and (dependent upon position) numbers get escaped as code points
703			return ch.slice( 0, -1 ) + "\\" + ch.charCodeAt( ch.length - 1 ).toString( 16 ) + " ";
704		}
705
706		// Other potentially-special ASCII characters get backslash-escaped
707		return "\\" + ch;
708	},
709
710	// Used for iframes
711	// See setDocument()
712	// Removing the function wrapper causes a "Permission Denied"
713	// error in IE
714	unloadHandler = function() {
715		setDocument();
716	},
717
718	disabledAncestor = addCombinator(
719		function( elem ) {
720			return elem.disabled === true && ("form" in elem || "label" in elem);
721		},
722		{ dir: "parentNode", next: "legend" }
723	);
724
725// Optimize for push.apply( _, NodeList )
726try {
727	push.apply(
728		(arr = slice.call( preferredDoc.childNodes )),
729		preferredDoc.childNodes
730	);
731	// Support: Android<4.0
732	// Detect silently failing push.apply
733	arr[ preferredDoc.childNodes.length ].nodeType;
734} catch ( e ) {
735	push = { apply: arr.length ?
736
737		// Leverage slice if possible
738		function( target, els ) {
739			push_native.apply( target, slice.call(els) );
740		} :
741
742		// Support: IE<9
743		// Otherwise append directly
744		function( target, els ) {
745			var j = target.length,
746				i = 0;
747			// Can't trust NodeList.length
748			while ( (target[j++] = els[i++]) ) {}
749			target.length = j - 1;
750		}
751	};
752}
753
754function Sizzle( selector, context, results, seed ) {
755	var m, i, elem, nid, match, groups, newSelector,
756		newContext = context && context.ownerDocument,
757
758		// nodeType defaults to 9, since context defaults to document
759		nodeType = context ? context.nodeType : 9;
760
761	results = results || [];
762
763	// Return early from calls with invalid selector or context
764	if ( typeof selector !== "string" || !selector ||
765		nodeType !== 1 && nodeType !== 9 && nodeType !== 11 ) {
766
767		return results;
768	}
769
770	// Try to shortcut find operations (as opposed to filters) in HTML documents
771	if ( !seed ) {
772
773		if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) {
774			setDocument( context );
775		}
776		context = context || document;
777
778		if ( documentIsHTML ) {
779
780			// If the selector is sufficiently simple, try using a "get*By*" DOM method
781			// (excepting DocumentFragment context, where the methods don't exist)
782			if ( nodeType !== 11 && (match = rquickExpr.exec( selector )) ) {
783
784				// ID selector
785				if ( (m = match[1]) ) {
786
787					// Document context
788					if ( nodeType === 9 ) {
789						if ( (elem = context.getElementById( m )) ) {
790
791							// Support: IE, Opera, Webkit
792							// TODO: identify versions
793							// getElementById can match elements by name instead of ID
794							if ( elem.id === m ) {
795								results.push( elem );
796								return results;
797							}
798						} else {
799							return results;
800						}
801
802					// Element context
803					} else {
804
805						// Support: IE, Opera, Webkit
806						// TODO: identify versions
807						// getElementById can match elements by name instead of ID
808						if ( newContext && (elem = newContext.getElementById( m )) &&
809							contains( context, elem ) &&
810							elem.id === m ) {
811
812							results.push( elem );
813							return results;
814						}
815					}
816
817				// Type selector
818				} else if ( match[2] ) {
819					push.apply( results, context.getElementsByTagName( selector ) );
820					return results;
821
822				// Class selector
823				} else if ( (m = match[3]) && support.getElementsByClassName &&
824					context.getElementsByClassName ) {
825
826					push.apply( results, context.getElementsByClassName( m ) );
827					return results;
828				}
829			}
830
831			// Take advantage of querySelectorAll
832			if ( support.qsa &&
833				!compilerCache[ selector + " " ] &&
834				(!rbuggyQSA || !rbuggyQSA.test( selector )) ) {
835
836				if ( nodeType !== 1 ) {
837					newContext = context;
838					newSelector = selector;
839
840				// qSA looks outside Element context, which is not what we want
841				// Thanks to Andrew Dupont for this workaround technique
842				// Support: IE <=8
843				// Exclude object elements
844				} else if ( context.nodeName.toLowerCase() !== "object" ) {
845
846					// Capture the context ID, setting it first if necessary
847					if ( (nid = context.getAttribute( "id" )) ) {
848						nid = nid.replace( rcssescape, fcssescape );
849					} else {
850						context.setAttribute( "id", (nid = expando) );
851					}
852
853					// Prefix every selector in the list
854					groups = tokenize( selector );
855					i = groups.length;
856					while ( i-- ) {
857						groups[i] = "#" + nid + " " + toSelector( groups[i] );
858					}
859					newSelector = groups.join( "," );
860
861					// Expand context for sibling selectors
862					newContext = rsibling.test( selector ) && testContext( context.parentNode ) ||
863						context;
864				}
865
866				if ( newSelector ) {
867					try {
868						push.apply( results,
869							newContext.querySelectorAll( newSelector )
870						);
871						return results;
872					} catch ( qsaError ) {
873					} finally {
874						if ( nid === expando ) {
875							context.removeAttribute( "id" );
876						}
877					}
878				}
879			}
880		}
881	}
882
883	// All others
884	return select( selector.replace( rtrim, "$1" ), context, results, seed );
885}
886
887/**
888 * Create key-value caches of limited size
889 * @returns {function(string, object)} Returns the Object data after storing it on itself with
890 *	property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength)
891 *	deleting the oldest entry
892 */
893function createCache() {
894	var keys = [];
895
896	function cache( key, value ) {
897		// Use (key + " ") to avoid collision with native prototype properties (see Issue #157)
898		if ( keys.push( key + " " ) > Expr.cacheLength ) {
899			// Only keep the most recent entries
900			delete cache[ keys.shift() ];
901		}
902		return (cache[ key + " " ] = value);
903	}
904	return cache;
905}
906
907/**
908 * Mark a function for special use by Sizzle
909 * @param {Function} fn The function to mark
910 */
911function markFunction( fn ) {
912	fn[ expando ] = true;
913	return fn;
914}
915
916/**
917 * Support testing using an element
918 * @param {Function} fn Passed the created element and returns a boolean result
919 */
920function assert( fn ) {
921	var el = document.createElement("fieldset");
922
923	try {
924		return !!fn( el );
925	} catch (e) {
926		return false;
927	} finally {
928		// Remove from its parent by default
929		if ( el.parentNode ) {
930			el.parentNode.removeChild( el );
931		}
932		// release memory in IE
933		el = null;
934	}
935}
936
937/**
938 * Adds the same handler for all of the specified attrs
939 * @param {String} attrs Pipe-separated list of attributes
940 * @param {Function} handler The method that will be applied
941 */
942function addHandle( attrs, handler ) {
943	var arr = attrs.split("|"),
944		i = arr.length;
945
946	while ( i-- ) {
947		Expr.attrHandle[ arr[i] ] = handler;
948	}
949}
950
951/**
952 * Checks document order of two siblings
953 * @param {Element} a
954 * @param {Element} b
955 * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b
956 */
957function siblingCheck( a, b ) {
958	var cur = b && a,
959		diff = cur && a.nodeType === 1 && b.nodeType === 1 &&
960			a.sourceIndex - b.sourceIndex;
961
962	// Use IE sourceIndex if available on both nodes
963	if ( diff ) {
964		return diff;
965	}
966
967	// Check if b follows a
968	if ( cur ) {
969		while ( (cur = cur.nextSibling) ) {
970			if ( cur === b ) {
971				return -1;
972			}
973		}
974	}
975
976	return a ? 1 : -1;
977}
978
979/**
980 * Returns a function to use in pseudos for input types
981 * @param {String} type
982 */
983function createInputPseudo( type ) {
984	return function( elem ) {
985		var name = elem.nodeName.toLowerCase();
986		return name === "input" && elem.type === type;
987	};
988}
989
990/**
991 * Returns a function to use in pseudos for buttons
992 * @param {String} type
993 */
994function createButtonPseudo( type ) {
995	return function( elem ) {
996		var name = elem.nodeName.toLowerCase();
997		return (name === "input" || name === "button") && elem.type === type;
998	};
999}
1000
1001/**
1002 * Returns a function to use in pseudos for :enabled/:disabled
1003 * @param {Boolean} disabled true for :disabled; false for :enabled
1004 */
1005function createDisabledPseudo( disabled ) {
1006
1007	// Known :disabled false positives: fieldset[disabled] > legend:nth-of-type(n+2) :can-disable
1008	return function( elem ) {
1009
1010		// Only certain elements can match :enabled or :disabled
1011		// https://html.spec.whatwg.org/multipage/scripting.html#selector-enabled
1012		// https://html.spec.whatwg.org/multipage/scripting.html#selector-disabled
1013		if ( "form" in elem ) {
1014
1015			// Check for inherited disabledness on relevant non-disabled elements:
1016			// * listed form-associated elements in a disabled fieldset
1017			//   https://html.spec.whatwg.org/multipage/forms.html#category-listed
1018			//   https://html.spec.whatwg.org/multipage/forms.html#concept-fe-disabled
1019			// * option elements in a disabled optgroup
1020			//   https://html.spec.whatwg.org/multipage/forms.html#concept-option-disabled
1021			// All such elements have a "form" property.
1022			if ( elem.parentNode && elem.disabled === false ) {
1023
1024				// Option elements defer to a parent optgroup if present
1025				if ( "label" in elem ) {
1026					if ( "label" in elem.parentNode ) {
1027						return elem.parentNode.disabled === disabled;
1028					} else {
1029						return elem.disabled === disabled;
1030					}
1031				}
1032
1033				// Support: IE 6 - 11
1034				// Use the isDisabled shortcut property to check for disabled fieldset ancestors
1035				return elem.isDisabled === disabled ||
1036
1037					// Where there is no isDisabled, check manually
1038					/* jshint -W018 */
1039					elem.isDisabled !== !disabled &&
1040						disabledAncestor( elem ) === disabled;
1041			}
1042
1043			return elem.disabled === disabled;
1044
1045		// Try to winnow out elements that can't be disabled before trusting the disabled property.
1046		// Some victims get caught in our net (label, legend, menu, track), but it shouldn't
1047		// even exist on them, let alone have a boolean value.
1048		} else if ( "label" in elem ) {
1049			return elem.disabled === disabled;
1050		}
1051
1052		// Remaining elements are neither :enabled nor :disabled
1053		return false;
1054	};
1055}
1056
1057/**
1058 * Returns a function to use in pseudos for positionals
1059 * @param {Function} fn
1060 */
1061function createPositionalPseudo( fn ) {
1062	return markFunction(function( argument ) {
1063		argument = +argument;
1064		return markFunction(function( seed, matches ) {
1065			var j,
1066				matchIndexes = fn( [], seed.length, argument ),
1067				i = matchIndexes.length;
1068
1069			// Match elements found at the specified indexes
1070			while ( i-- ) {
1071				if ( seed[ (j = matchIndexes[i]) ] ) {
1072					seed[j] = !(matches[j] = seed[j]);
1073				}
1074			}
1075		});
1076	});
1077}
1078
1079/**
1080 * Checks a node for validity as a Sizzle context
1081 * @param {Element|Object=} context
1082 * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value
1083 */
1084function testContext( context ) {
1085	return context && typeof context.getElementsByTagName !== "undefined" && context;
1086}
1087
1088// Expose support vars for convenience
1089support = Sizzle.support = {};
1090
1091/**
1092 * Detects XML nodes
1093 * @param {Element|Object} elem An element or a document
1094 * @returns {Boolean} True iff elem is a non-HTML XML node
1095 */
1096isXML = Sizzle.isXML = function( elem ) {
1097	// documentElement is verified for cases where it doesn't yet exist
1098	// (such as loading iframes in IE - #4833)
1099	var documentElement = elem && (elem.ownerDocument || elem).documentElement;
1100	return documentElement ? documentElement.nodeName !== "HTML" : false;
1101};
1102
1103/**
1104 * Sets document-related variables once based on the current document
1105 * @param {Element|Object} [doc] An element or document object to use to set the document
1106 * @returns {Object} Returns the current document
1107 */
1108setDocument = Sizzle.setDocument = function( node ) {
1109	var hasCompare, subWindow,
1110		doc = node ? node.ownerDocument || node : preferredDoc;
1111
1112	// Return early if doc is invalid or already selected
1113	if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) {
1114		return document;
1115	}
1116
1117	// Update global variables
1118	document = doc;
1119	docElem = document.documentElement;
1120	documentIsHTML = !isXML( document );
1121
1122	// Support: IE 9-11, Edge
1123	// Accessing iframe documents after unload throws "permission denied" errors (jQuery #13936)
1124	if ( preferredDoc !== document &&
1125		(subWindow = document.defaultView) && subWindow.top !== subWindow ) {
1126
1127		// Support: IE 11, Edge
1128		if ( subWindow.addEventListener ) {
1129			subWindow.addEventListener( "unload", unloadHandler, false );
1130
1131		// Support: IE 9 - 10 only
1132		} else if ( subWindow.attachEvent ) {
1133			subWindow.attachEvent( "onunload", unloadHandler );
1134		}
1135	}
1136
1137	/* Attributes
1138	---------------------------------------------------------------------- */
1139
1140	// Support: IE<8
1141	// Verify that getAttribute really returns attributes and not properties
1142	// (excepting IE8 booleans)
1143	support.attributes = assert(function( el ) {
1144		el.className = "i";
1145		return !el.getAttribute("className");
1146	});
1147
1148	/* getElement(s)By*
1149	---------------------------------------------------------------------- */
1150
1151	// Check if getElementsByTagName("*") returns only elements
1152	support.getElementsByTagName = assert(function( el ) {
1153		el.appendChild( document.createComment("") );
1154		return !el.getElementsByTagName("*").length;
1155	});
1156
1157	// Support: IE<9
1158	support.getElementsByClassName = rnative.test( document.getElementsByClassName );
1159
1160	// Support: IE<10
1161	// Check if getElementById returns elements by name
1162	// The broken getElementById methods don't pick up programmatically-set names,
1163	// so use a roundabout getElementsByName test
1164	support.getById = assert(function( el ) {
1165		docElem.appendChild( el ).id = expando;
1166		return !document.getElementsByName || !document.getElementsByName( expando ).length;
1167	});
1168
1169	// ID filter and find
1170	if ( support.getById ) {
1171		Expr.filter["ID"] = function( id ) {
1172			var attrId = id.replace( runescape, funescape );
1173			return function( elem ) {
1174				return elem.getAttribute("id") === attrId;
1175			};
1176		};
1177		Expr.find["ID"] = function( id, context ) {
1178			if ( typeof context.getElementById !== "undefined" && documentIsHTML ) {
1179				var elem = context.getElementById( id );
1180				return elem ? [ elem ] : [];
1181			}
1182		};
1183	} else {
1184		Expr.filter["ID"] =  function( id ) {
1185			var attrId = id.replace( runescape, funescape );
1186			return function( elem ) {
1187				var node = typeof elem.getAttributeNode !== "undefined" &&
1188					elem.getAttributeNode("id");
1189				return node && node.value === attrId;
1190			};
1191		};
1192
1193		// Support: IE 6 - 7 only
1194		// getElementById is not reliable as a find shortcut
1195		Expr.find["ID"] = function( id, context ) {
1196			if ( typeof context.getElementById !== "undefined" && documentIsHTML ) {
1197				var node, i, elems,
1198					elem = context.getElementById( id );
1199
1200				if ( elem ) {
1201
1202					// Verify the id attribute
1203					node = elem.getAttributeNode("id");
1204					if ( node && node.value === id ) {
1205						return [ elem ];
1206					}
1207
1208					// Fall back on getElementsByName
1209					elems = context.getElementsByName( id );
1210					i = 0;
1211					while ( (elem = elems[i++]) ) {
1212						node = elem.getAttributeNode("id");
1213						if ( node && node.value === id ) {
1214							return [ elem ];
1215						}
1216					}
1217				}
1218
1219				return [];
1220			}
1221		};
1222	}
1223
1224	// Tag
1225	Expr.find["TAG"] = support.getElementsByTagName ?
1226		function( tag, context ) {
1227			if ( typeof context.getElementsByTagName !== "undefined" ) {
1228				return context.getElementsByTagName( tag );
1229
1230			// DocumentFragment nodes don't have gEBTN
1231			} else if ( support.qsa ) {
1232				return context.querySelectorAll( tag );
1233			}
1234		} :
1235
1236		function( tag, context ) {
1237			var elem,
1238				tmp = [],
1239				i = 0,
1240				// By happy coincidence, a (broken) gEBTN appears on DocumentFragment nodes too
1241				results = context.getElementsByTagName( tag );
1242
1243			// Filter out possible comments
1244			if ( tag === "*" ) {
1245				while ( (elem = results[i++]) ) {
1246					if ( elem.nodeType === 1 ) {
1247						tmp.push( elem );
1248					}
1249				}
1250
1251				return tmp;
1252			}
1253			return results;
1254		};
1255
1256	// Class
1257	Expr.find["CLASS"] = support.getElementsByClassName && function( className, context ) {
1258		if ( typeof context.getElementsByClassName !== "undefined" && documentIsHTML ) {
1259			return context.getElementsByClassName( className );
1260		}
1261	};
1262
1263	/* QSA/matchesSelector
1264	---------------------------------------------------------------------- */
1265
1266	// QSA and matchesSelector support
1267
1268	// matchesSelector(:active) reports false when true (IE9/Opera 11.5)
1269	rbuggyMatches = [];
1270
1271	// qSa(:focus) reports false when true (Chrome 21)
1272	// We allow this because of a bug in IE8/9 that throws an error
1273	// whenever `document.activeElement` is accessed on an iframe
1274	// So, we allow :focus to pass through QSA all the time to avoid the IE error
1275	// See https://bugs.jquery.com/ticket/13378
1276	rbuggyQSA = [];
1277
1278	if ( (support.qsa = rnative.test( document.querySelectorAll )) ) {
1279		// Build QSA regex
1280		// Regex strategy adopted from Diego Perini
1281		assert(function( el ) {
1282			// Select is set to empty string on purpose
1283			// This is to test IE's treatment of not explicitly
1284			// setting a boolean content attribute,
1285			// since its presence should be enough
1286			// https://bugs.jquery.com/ticket/12359
1287			docElem.appendChild( el ).innerHTML = "<a id='" + expando + "'></a>" +
1288				"<select id='" + expando + "-\r\\' msallowcapture=''>" +
1289				"<option selected=''></option></select>";
1290
1291			// Support: IE8, Opera 11-12.16
1292			// Nothing should be selected when empty strings follow ^= or $= or *=
1293			// The test attribute must be unknown in Opera but "safe" for WinRT
1294			// https://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section
1295			if ( el.querySelectorAll("[msallowcapture^='']").length ) {
1296				rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" );
1297			}
1298
1299			// Support: IE8
1300			// Boolean attributes and "value" are not treated correctly
1301			if ( !el.querySelectorAll("[selected]").length ) {
1302				rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" );
1303			}
1304
1305			// Support: Chrome<29, Android<4.4, Safari<7.0+, iOS<7.0+, PhantomJS<1.9.8+
1306			if ( !el.querySelectorAll( "[id~=" + expando + "-]" ).length ) {
1307				rbuggyQSA.push("~=");
1308			}
1309
1310			// Webkit/Opera - :checked should return selected option elements
1311			// http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
1312			// IE8 throws error here and will not see later tests
1313			if ( !el.querySelectorAll(":checked").length ) {
1314				rbuggyQSA.push(":checked");
1315			}
1316
1317			// Support: Safari 8+, iOS 8+
1318			// https://bugs.webkit.org/show_bug.cgi?id=136851
1319			// In-page `selector#id sibling-combinator selector` fails
1320			if ( !el.querySelectorAll( "a#" + expando + "+*" ).length ) {
1321				rbuggyQSA.push(".#.+[+~]");
1322			}
1323		});
1324
1325		assert(function( el ) {
1326			el.innerHTML = "<a href='' disabled='disabled'></a>" +
1327				"<select disabled='disabled'><option/></select>";
1328
1329			// Support: Windows 8 Native Apps
1330			// The type and name attributes are restricted during .innerHTML assignment
1331			var input = document.createElement("input");
1332			input.setAttribute( "type", "hidden" );
1333			el.appendChild( input ).setAttribute( "name", "D" );
1334
1335			// Support: IE8
1336			// Enforce case-sensitivity of name attribute
1337			if ( el.querySelectorAll("[name=d]").length ) {
1338				rbuggyQSA.push( "name" + whitespace + "*[*^$|!~]?=" );
1339			}
1340
1341			// FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled)
1342			// IE8 throws error here and will not see later tests
1343			if ( el.querySelectorAll(":enabled").length !== 2 ) {
1344				rbuggyQSA.push( ":enabled", ":disabled" );
1345			}
1346
1347			// Support: IE9-11+
1348			// IE's :disabled selector does not pick up the children of disabled fieldsets
1349			docElem.appendChild( el ).disabled = true;
1350			if ( el.querySelectorAll(":disabled").length !== 2 ) {
1351				rbuggyQSA.push( ":enabled", ":disabled" );
1352			}
1353
1354			// Opera 10-11 does not throw on post-comma invalid pseudos
1355			el.querySelectorAll("*,:x");
1356			rbuggyQSA.push(",.*:");
1357		});
1358	}
1359
1360	if ( (support.matchesSelector = rnative.test( (matches = docElem.matches ||
1361		docElem.webkitMatchesSelector ||
1362		docElem.mozMatchesSelector ||
1363		docElem.oMatchesSelector ||
1364		docElem.msMatchesSelector) )) ) {
1365
1366		assert(function( el ) {
1367			// Check to see if it's possible to do matchesSelector
1368			// on a disconnected node (IE 9)
1369			support.disconnectedMatch = matches.call( el, "*" );
1370
1371			// This should fail with an exception
1372			// Gecko does not error, returns false instead
1373			matches.call( el, "[s!='']:x" );
1374			rbuggyMatches.push( "!=", pseudos );
1375		});
1376	}
1377
1378	rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join("|") );
1379	rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join("|") );
1380
1381	/* Contains
1382	---------------------------------------------------------------------- */
1383	hasCompare = rnative.test( docElem.compareDocumentPosition );
1384
1385	// Element contains another
1386	// Purposefully self-exclusive
1387	// As in, an element does not contain itself
1388	contains = hasCompare || rnative.test( docElem.contains ) ?
1389		function( a, b ) {
1390			var adown = a.nodeType === 9 ? a.documentElement : a,
1391				bup = b && b.parentNode;
1392			return a === bup || !!( bup && bup.nodeType === 1 && (
1393				adown.contains ?
1394					adown.contains( bup ) :
1395					a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16
1396			));
1397		} :
1398		function( a, b ) {
1399			if ( b ) {
1400				while ( (b = b.parentNode) ) {
1401					if ( b === a ) {
1402						return true;
1403					}
1404				}
1405			}
1406			return false;
1407		};
1408
1409	/* Sorting
1410	---------------------------------------------------------------------- */
1411
1412	// Document order sorting
1413	sortOrder = hasCompare ?
1414	function( a, b ) {
1415
1416		// Flag for duplicate removal
1417		if ( a === b ) {
1418			hasDuplicate = true;
1419			return 0;
1420		}
1421
1422		// Sort on method existence if only one input has compareDocumentPosition
1423		var compare = !a.compareDocumentPosition - !b.compareDocumentPosition;
1424		if ( compare ) {
1425			return compare;
1426		}
1427
1428		// Calculate position if both inputs belong to the same document
1429		compare = ( a.ownerDocument || a ) === ( b.ownerDocument || b ) ?
1430			a.compareDocumentPosition( b ) :
1431
1432			// Otherwise we know they are disconnected
1433			1;
1434
1435		// Disconnected nodes
1436		if ( compare & 1 ||
1437			(!support.sortDetached && b.compareDocumentPosition( a ) === compare) ) {
1438
1439			// Choose the first element that is related to our preferred document
1440			if ( a === document || a.ownerDocument === preferredDoc && contains(preferredDoc, a) ) {
1441				return -1;
1442			}
1443			if ( b === document || b.ownerDocument === preferredDoc && contains(preferredDoc, b) ) {
1444				return 1;
1445			}
1446
1447			// Maintain original order
1448			return sortInput ?
1449				( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) :
1450				0;
1451		}
1452
1453		return compare & 4 ? -1 : 1;
1454	} :
1455	function( a, b ) {
1456		// Exit early if the nodes are identical
1457		if ( a === b ) {
1458			hasDuplicate = true;
1459			return 0;
1460		}
1461
1462		var cur,
1463			i = 0,
1464			aup = a.parentNode,
1465			bup = b.parentNode,
1466			ap = [ a ],
1467			bp = [ b ];
1468
1469		// Parentless nodes are either documents or disconnected
1470		if ( !aup || !bup ) {
1471			return a === document ? -1 :
1472				b === document ? 1 :
1473				aup ? -1 :
1474				bup ? 1 :
1475				sortInput ?
1476				( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) :
1477				0;
1478
1479		// If the nodes are siblings, we can do a quick check
1480		} else if ( aup === bup ) {
1481			return siblingCheck( a, b );
1482		}
1483
1484		// Otherwise we need full lists of their ancestors for comparison
1485		cur = a;
1486		while ( (cur = cur.parentNode) ) {
1487			ap.unshift( cur );
1488		}
1489		cur = b;
1490		while ( (cur = cur.parentNode) ) {
1491			bp.unshift( cur );
1492		}
1493
1494		// Walk down the tree looking for a discrepancy
1495		while ( ap[i] === bp[i] ) {
1496			i++;
1497		}
1498
1499		return i ?
1500			// Do a sibling check if the nodes have a common ancestor
1501			siblingCheck( ap[i], bp[i] ) :
1502
1503			// Otherwise nodes in our document sort first
1504			ap[i] === preferredDoc ? -1 :
1505			bp[i] === preferredDoc ? 1 :
1506			0;
1507	};
1508
1509	return document;
1510};
1511
1512Sizzle.matches = function( expr, elements ) {
1513	return Sizzle( expr, null, null, elements );
1514};
1515
1516Sizzle.matchesSelector = function( elem, expr ) {
1517	// Set document vars if needed
1518	if ( ( elem.ownerDocument || elem ) !== document ) {
1519		setDocument( elem );
1520	}
1521
1522	// Make sure that attribute selectors are quoted
1523	expr = expr.replace( rattributeQuotes, "='$1']" );
1524
1525	if ( support.matchesSelector && documentIsHTML &&
1526		!compilerCache[ expr + " " ] &&
1527		( !rbuggyMatches || !rbuggyMatches.test( expr ) ) &&
1528		( !rbuggyQSA     || !rbuggyQSA.test( expr ) ) ) {
1529
1530		try {
1531			var ret = matches.call( elem, expr );
1532
1533			// IE 9's matchesSelector returns false on disconnected nodes
1534			if ( ret || support.disconnectedMatch ||
1535					// As well, disconnected nodes are said to be in a document
1536					// fragment in IE 9
1537					elem.document && elem.document.nodeType !== 11 ) {
1538				return ret;
1539			}
1540		} catch (e) {}
1541	}
1542
1543	return Sizzle( expr, document, null, [ elem ] ).length > 0;
1544};
1545
1546Sizzle.contains = function( context, elem ) {
1547	// Set document vars if needed
1548	if ( ( context.ownerDocument || context ) !== document ) {
1549		setDocument( context );
1550	}
1551	return contains( context, elem );
1552};
1553
1554Sizzle.attr = function( elem, name ) {
1555	// Set document vars if needed
1556	if ( ( elem.ownerDocument || elem ) !== document ) {
1557		setDocument( elem );
1558	}
1559
1560	var fn = Expr.attrHandle[ name.toLowerCase() ],
1561		// Don't get fooled by Object.prototype properties (jQuery #13807)
1562		val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ?
1563			fn( elem, name, !documentIsHTML ) :
1564			undefined;
1565
1566	return val !== undefined ?
1567		val :
1568		support.attributes || !documentIsHTML ?
1569			elem.getAttribute( name ) :
1570			(val = elem.getAttributeNode(name)) && val.specified ?
1571				val.value :
1572				null;
1573};
1574
1575Sizzle.escape = function( sel ) {
1576	return (sel + "").replace( rcssescape, fcssescape );
1577};
1578
1579Sizzle.error = function( msg ) {
1580	throw new Error( "Syntax error, unrecognized expression: " + msg );
1581};
1582
1583/**
1584 * Document sorting and removing duplicates
1585 * @param {ArrayLike} results
1586 */
1587Sizzle.uniqueSort = function( results ) {
1588	var elem,
1589		duplicates = [],
1590		j = 0,
1591		i = 0;
1592
1593	// Unless we *know* we can detect duplicates, assume their presence
1594	hasDuplicate = !support.detectDuplicates;
1595	sortInput = !support.sortStable && results.slice( 0 );
1596	results.sort( sortOrder );
1597
1598	if ( hasDuplicate ) {
1599		while ( (elem = results[i++]) ) {
1600			if ( elem === results[ i ] ) {
1601				j = duplicates.push( i );
1602			}
1603		}
1604		while ( j-- ) {
1605			results.splice( duplicates[ j ], 1 );
1606		}
1607	}
1608
1609	// Clear input after sorting to release objects
1610	// See https://github.com/jquery/sizzle/pull/225
1611	sortInput = null;
1612
1613	return results;
1614};
1615
1616/**
1617 * Utility function for retrieving the text value of an array of DOM nodes
1618 * @param {Array|Element} elem
1619 */
1620getText = Sizzle.getText = function( elem ) {
1621	var node,
1622		ret = "",
1623		i = 0,
1624		nodeType = elem.nodeType;
1625
1626	if ( !nodeType ) {
1627		// If no nodeType, this is expected to be an array
1628		while ( (node = elem[i++]) ) {
vendor: 11,976 bytes, lines 1629-2027
1629			// Do not traverse comment nodes
1630			ret += getText( node );
1631		}
1632	} else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) {
1633		// Use textContent for elements
1634		// innerText usage removed for consistency of new lines (jQuery #11153)
1635		if ( typeof elem.textContent === "string" ) {
1636			return elem.textContent;
1637		} else {
1638			// Traverse its children
1639			for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
1640				ret += getText( elem );
1641			}
1642		}
1643	} else if ( nodeType === 3 || nodeType === 4 ) {
1644		return elem.nodeValue;
1645	}
1646	// Do not include comment or processing instruction nodes
1647
1648	return ret;
1649};
1650
1651Expr = Sizzle.selectors = {
1652
1653	// Can be adjusted by the user
1654	cacheLength: 50,
1655
1656	createPseudo: markFunction,
1657
1658	match: matchExpr,
1659
1660	attrHandle: {},
1661
1662	find: {},
1663
1664	relative: {
1665		">": { dir: "parentNode", first: true },
1666		" ": { dir: "parentNode" },
1667		"+": { dir: "previousSibling", first: true },
1668		"~": { dir: "previousSibling" }
1669	},
1670
1671	preFilter: {
1672		"ATTR": function( match ) {
1673			match[1] = match[1].replace( runescape, funescape );
1674
1675			// Move the given value to match[3] whether quoted or unquoted
1676			match[3] = ( match[3] || match[4] || match[5] || "" ).replace( runescape, funescape );
1677
1678			if ( match[2] === "~=" ) {
1679				match[3] = " " + match[3] + " ";
1680			}
1681
1682			return match.slice( 0, 4 );
1683		},
1684
1685		"CHILD": function( match ) {
1686			/* matches from matchExpr["CHILD"]
1687				1 type (only|nth|...)
1688				2 what (child|of-type)
1689				3 argument (even|odd|\d*|\d*n([+-]\d+)?|...)
1690				4 xn-component of xn+y argument ([+-]?\d*n|)
1691				5 sign of xn-component
1692				6 x of xn-component
1693				7 sign of y-component
1694				8 y of y-component
1695			*/
1696			match[1] = match[1].toLowerCase();
1697
1698			if ( match[1].slice( 0, 3 ) === "nth" ) {
1699				// nth-* requires argument
1700				if ( !match[3] ) {
1701					Sizzle.error( match[0] );
1702				}
1703
1704				// numeric x and y parameters for Expr.filter.CHILD
1705				// remember that false/true cast respectively to 0/1
1706				match[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === "even" || match[3] === "odd" ) );
1707				match[5] = +( ( match[7] + match[8] ) || match[3] === "odd" );
1708
1709			// other types prohibit arguments
1710			} else if ( match[3] ) {
1711				Sizzle.error( match[0] );
1712			}
1713
1714			return match;
1715		},
1716
1717		"PSEUDO": function( match ) {
1718			var excess,
1719				unquoted = !match[6] && match[2];
1720
1721			if ( matchExpr["CHILD"].test( match[0] ) ) {
1722				return null;
1723			}
1724
1725			// Accept quoted arguments as-is
1726			if ( match[3] ) {
1727				match[2] = match[4] || match[5] || "";
1728
1729			// Strip excess characters from unquoted arguments
1730			} else if ( unquoted && rpseudo.test( unquoted ) &&
1731				// Get excess from tokenize (recursively)
1732				(excess = tokenize( unquoted, true )) &&
1733				// advance to the next closing parenthesis
1734				(excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length) ) {
1735
1736				// excess is a negative index
1737				match[0] = match[0].slice( 0, excess );
1738				match[2] = unquoted.slice( 0, excess );
1739			}
1740
1741			// Return only captures needed by the pseudo filter method (type and argument)
1742			return match.slice( 0, 3 );
1743		}
1744	},
1745
1746	filter: {
1747
1748		"TAG": function( nodeNameSelector ) {
1749			var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase();
1750			return nodeNameSelector === "*" ?
1751				function() { return true; } :
1752				function( elem ) {
1753					return elem.nodeName && elem.nodeName.toLowerCase() === nodeName;
1754				};
1755		},
1756
1757		"CLASS": function( className ) {
1758			var pattern = classCache[ className + " " ];
1759
1760			return pattern ||
1761				(pattern = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" )) &&
1762				classCache( className, function( elem ) {
1763					return pattern.test( typeof elem.className === "string" && elem.className || typeof elem.getAttribute !== "undefined" && elem.getAttribute("class") || "" );
1764				});
1765		},
1766
1767		"ATTR": function( name, operator, check ) {
1768			return function( elem ) {
1769				var result = Sizzle.attr( elem, name );
1770
1771				if ( result == null ) {
1772					return operator === "!=";
1773				}
1774				if ( !operator ) {
1775					return true;
1776				}
1777
1778				result += "";
1779
1780				return operator === "=" ? result === check :
1781					operator === "!=" ? result !== check :
1782					operator === "^=" ? check && result.indexOf( check ) === 0 :
1783					operator === "*=" ? check && result.indexOf( check ) > -1 :
1784					operator === "$=" ? check && result.slice( -check.length ) === check :
1785					operator === "~=" ? ( " " + result.replace( rwhitespace, " " ) + " " ).indexOf( check ) > -1 :
1786					operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" :
1787					false;
1788			};
1789		},
1790
1791		"CHILD": function( type, what, argument, first, last ) {
1792			var simple = type.slice( 0, 3 ) !== "nth",
1793				forward = type.slice( -4 ) !== "last",
1794				ofType = what === "of-type";
1795
1796			return first === 1 && last === 0 ?
1797
1798				// Shortcut for :nth-*(n)
1799				function( elem ) {
1800					return !!elem.parentNode;
1801				} :
1802
1803				function( elem, context, xml ) {
1804					var cache, uniqueCache, outerCache, node, nodeIndex, start,
1805						dir = simple !== forward ? "nextSibling" : "previousSibling",
1806						parent = elem.parentNode,
1807						name = ofType && elem.nodeName.toLowerCase(),
1808						useCache = !xml && !ofType,
1809						diff = false;
1810
1811					if ( parent ) {
1812
1813						// :(first|last|only)-(child|of-type)
1814						if ( simple ) {
1815							while ( dir ) {
1816								node = elem;
1817								while ( (node = node[ dir ]) ) {
1818									if ( ofType ?
1819										node.nodeName.toLowerCase() === name :
1820										node.nodeType === 1 ) {
1821
1822										return false;
1823									}
1824								}
1825								// Reverse direction for :only-* (if we haven't yet done so)
1826								start = dir = type === "only" && !start && "nextSibling";
1827							}
1828							return true;
1829						}
1830
1831						start = [ forward ? parent.firstChild : parent.lastChild ];
1832
1833						// non-xml :nth-child(...) stores cache data on `parent`
1834						if ( forward && useCache ) {
1835
1836							// Seek `elem` from a previously-cached index
1837
1838							// ...in a gzip-friendly way
1839							node = parent;
1840							outerCache = node[ expando ] || (node[ expando ] = {});
1841
1842							// Support: IE <9 only
1843							// Defend against cloned attroperties (jQuery gh-1709)
1844							uniqueCache = outerCache[ node.uniqueID ] ||
1845								(outerCache[ node.uniqueID ] = {});
1846
1847							cache = uniqueCache[ type ] || [];
1848							nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ];
1849							diff = nodeIndex && cache[ 2 ];
1850							node = nodeIndex && parent.childNodes[ nodeIndex ];
1851
1852							while ( (node = ++nodeIndex && node && node[ dir ] ||
1853
1854								// Fallback to seeking `elem` from the start
1855								(diff = nodeIndex = 0) || start.pop()) ) {
1856
1857								// When found, cache indexes on `parent` and break
1858								if ( node.nodeType === 1 && ++diff && node === elem ) {
1859									uniqueCache[ type ] = [ dirruns, nodeIndex, diff ];
1860									break;
1861								}
1862							}
1863
1864						} else {
1865							// Use previously-cached element index if available
1866							if ( useCache ) {
1867								// ...in a gzip-friendly way
1868								node = elem;
1869								outerCache = node[ expando ] || (node[ expando ] = {});
1870
1871								// Support: IE <9 only
1872								// Defend against cloned attroperties (jQuery gh-1709)
1873								uniqueCache = outerCache[ node.uniqueID ] ||
1874									(outerCache[ node.uniqueID ] = {});
1875
1876								cache = uniqueCache[ type ] || [];
1877								nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ];
1878								diff = nodeIndex;
1879							}
1880
1881							// xml :nth-child(...)
1882							// or :nth-last-child(...) or :nth(-last)?-of-type(...)
1883							if ( diff === false ) {
1884								// Use the same loop as above to seek `elem` from the start
1885								while ( (node = ++nodeIndex && node && node[ dir ] ||
1886									(diff = nodeIndex = 0) || start.pop()) ) {
1887
1888									if ( ( ofType ?
1889										node.nodeName.toLowerCase() === name :
1890										node.nodeType === 1 ) &&
1891										++diff ) {
1892
1893										// Cache the index of each encountered element
1894										if ( useCache ) {
1895											outerCache = node[ expando ] || (node[ expando ] = {});
1896
1897											// Support: IE <9 only
1898											// Defend against cloned attroperties (jQuery gh-1709)
1899											uniqueCache = outerCache[ node.uniqueID ] ||
1900												(outerCache[ node.uniqueID ] = {});
1901
1902											uniqueCache[ type ] = [ dirruns, diff ];
1903										}
1904
1905										if ( node === elem ) {
1906											break;
1907										}
1908									}
1909								}
1910							}
1911						}
1912
1913						// Incorporate the offset, then check against cycle size
1914						diff -= last;
1915						return diff === first || ( diff % first === 0 && diff / first >= 0 );
1916					}
1917				};
1918		},
1919
1920		"PSEUDO": function( pseudo, argument ) {
1921			// pseudo-class names are case-insensitive
1922			// http://www.w3.org/TR/selectors/#pseudo-classes
1923			// Prioritize by case sensitivity in case custom pseudos are added with uppercase letters
1924			// Remember that setFilters inherits from pseudos
1925			var args,
1926				fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] ||
1927					Sizzle.error( "unsupported pseudo: " + pseudo );
1928
1929			// The user may use createPseudo to indicate that
1930			// arguments are needed to create the filter function
1931			// just as Sizzle does
1932			if ( fn[ expando ] ) {
1933				return fn( argument );
1934			}
1935
1936			// But maintain support for old signatures
1937			if ( fn.length > 1 ) {
1938				args = [ pseudo, pseudo, "", argument ];
1939				return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ?
1940					markFunction(function( seed, matches ) {
1941						var idx,
1942							matched = fn( seed, argument ),
1943							i = matched.length;
1944						while ( i-- ) {
1945							idx = indexOf( seed, matched[i] );
1946							seed[ idx ] = !( matches[ idx ] = matched[i] );
1947						}
1948					}) :
1949					function( elem ) {
1950						return fn( elem, 0, args );
1951					};
1952			}
1953
1954			return fn;
1955		}
1956	},
1957
1958	pseudos: {
1959		// Potentially complex pseudos
1960		"not": markFunction(function( selector ) {
1961			// Trim the selector passed to compile
1962			// to avoid treating leading and trailing
1963			// spaces as combinators
1964			var input = [],
1965				results = [],
1966				matcher = compile( selector.replace( rtrim, "$1" ) );
1967
1968			return matcher[ expando ] ?
1969				markFunction(function( seed, matches, context, xml ) {
1970					var elem,
1971						unmatched = matcher( seed, null, xml, [] ),
1972						i = seed.length;
1973
1974					// Match elements unmatched by `matcher`
1975					while ( i-- ) {
1976						if ( (elem = unmatched[i]) ) {
1977							seed[i] = !(matches[i] = elem);
1978						}
1979					}
1980				}) :
1981				function( elem, context, xml ) {
1982					input[0] = elem;
1983					matcher( input, null, xml, results );
1984					// Don't keep the element (issue #299)
1985					input[0] = null;
1986					return !results.pop();
1987				};
1988		}),
1989
1990		"has": markFunction(function( selector ) {
1991			return function( elem ) {
1992				return Sizzle( selector, elem ).length > 0;
1993			};
1994		}),
1995
1996		"contains": markFunction(function( text ) {
1997			text = text.replace( runescape, funescape );
1998			return function( elem ) {
1999				return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1;
2000			};
2001		}),
2002
2003		// "Whether an element is represented by a :lang() selector
2004		// is based solely on the element's language value
2005		// being equal to the identifier C,
2006		// or beginning with the identifier C immediately followed by "-".
2007		// The matching of C against the element's language value is performed case-insensitively.
2008		// The identifier C does not have to be a valid language name."
2009		// http://www.w3.org/TR/selectors/#lang-pseudo
2010		"lang": markFunction( function( lang ) {
2011			// lang value must be a valid identifier
2012			if ( !ridentifier.test(lang || "") ) {
2013				Sizzle.error( "unsupported lang: " + lang );
2014			}
2015			lang = lang.replace( runescape, funescape ).toLowerCase();
2016			return function( elem ) {
2017				var elemLang;
2018				do {
2019					if ( (elemLang = documentIsHTML ?
2020						elem.lang :
2021						elem.getAttribute("xml:lang") || elem.getAttribute("lang")) ) {
2022
2023						elemLang = elemLang.toLowerCase();
2024						return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0;
2025					}
2026				} while ( (elem = elem.parentNode) && elem.nodeType === 1 );
2027				return false;
vendor: 22,724 bytes, lines 2028-2850
2028			};
2029		}),
2030
2031		// Miscellaneous
2032		"target": function( elem ) {
2033			var hash = window.location && window.location.hash;
2034			return hash && hash.slice( 1 ) === elem.id;
2035		},
2036
2037		"root": function( elem ) {
2038			return elem === docElem;
2039		},
2040
2041		"focus": function( elem ) {
2042			return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex);
2043		},
2044
2045		// Boolean properties
2046		"enabled": createDisabledPseudo( false ),
2047		"disabled": createDisabledPseudo( true ),
2048
2049		"checked": function( elem ) {
2050			// In CSS3, :checked should return both checked and selected elements
2051			// http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
2052			var nodeName = elem.nodeName.toLowerCase();
2053			return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected);
2054		},
2055
2056		"selected": function( elem ) {
2057			// Accessing this property makes selected-by-default
2058			// options in Safari work properly
2059			if ( elem.parentNode ) {
2060				elem.parentNode.selectedIndex;
2061			}
2062
2063			return elem.selected === true;
2064		},
2065
2066		// Contents
2067		"empty": function( elem ) {
2068			// http://www.w3.org/TR/selectors/#empty-pseudo
2069			// :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5),
2070			//   but not by others (comment: 8; processing instruction: 7; etc.)
2071			// nodeType < 6 works because attributes (2) do not appear as children
2072			for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
2073				if ( elem.nodeType < 6 ) {
2074					return false;
2075				}
2076			}
2077			return true;
2078		},
2079
2080		"parent": function( elem ) {
2081			return !Expr.pseudos["empty"]( elem );
2082		},
2083
2084		// Element/input types
2085		"header": function( elem ) {
2086			return rheader.test( elem.nodeName );
2087		},
2088
2089		"input": function( elem ) {
2090			return rinputs.test( elem.nodeName );
2091		},
2092
2093		"button": function( elem ) {
2094			var name = elem.nodeName.toLowerCase();
2095			return name === "input" && elem.type === "button" || name === "button";
2096		},
2097
2098		"text": function( elem ) {
2099			var attr;
2100			return elem.nodeName.toLowerCase() === "input" &&
2101				elem.type === "text" &&
2102
2103				// Support: IE<8
2104				// New HTML5 attribute values (e.g., "search") appear with elem.type === "text"
2105				( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === "text" );
2106		},
2107
2108		// Position-in-collection
2109		"first": createPositionalPseudo(function() {
2110			return [ 0 ];
2111		}),
2112
2113		"last": createPositionalPseudo(function( matchIndexes, length ) {
2114			return [ length - 1 ];
2115		}),
2116
2117		"eq": createPositionalPseudo(function( matchIndexes, length, argument ) {
2118			return [ argument < 0 ? argument + length : argument ];
2119		}),
2120
2121		"even": createPositionalPseudo(function( matchIndexes, length ) {
2122			var i = 0;
2123			for ( ; i < length; i += 2 ) {
2124				matchIndexes.push( i );
2125			}
2126			return matchIndexes;
2127		}),
2128
2129		"odd": createPositionalPseudo(function( matchIndexes, length ) {
2130			var i = 1;
2131			for ( ; i < length; i += 2 ) {
2132				matchIndexes.push( i );
2133			}
2134			return matchIndexes;
2135		}),
2136
2137		"lt": createPositionalPseudo(function( matchIndexes, length, argument ) {
2138			var i = argument < 0 ? argument + length : argument;
2139			for ( ; --i >= 0; ) {
2140				matchIndexes.push( i );
2141			}
2142			return matchIndexes;
2143		}),
2144
2145		"gt": createPositionalPseudo(function( matchIndexes, length, argument ) {
2146			var i = argument < 0 ? argument + length : argument;
2147			for ( ; ++i < length; ) {
2148				matchIndexes.push( i );
2149			}
2150			return matchIndexes;
2151		})
2152	}
2153};
2154
2155Expr.pseudos["nth"] = Expr.pseudos["eq"];
2156
2157// Add button/input type pseudos
2158for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) {
2159	Expr.pseudos[ i ] = createInputPseudo( i );
2160}
2161for ( i in { submit: true, reset: true } ) {
2162	Expr.pseudos[ i ] = createButtonPseudo( i );
2163}
2164
2165// Easy API for creating new setFilters
2166function setFilters() {}
2167setFilters.prototype = Expr.filters = Expr.pseudos;
2168Expr.setFilters = new setFilters();
2169
2170tokenize = Sizzle.tokenize = function( selector, parseOnly ) {
2171	var matched, match, tokens, type,
2172		soFar, groups, preFilters,
2173		cached = tokenCache[ selector + " " ];
2174
2175	if ( cached ) {
2176		return parseOnly ? 0 : cached.slice( 0 );
2177	}
2178
2179	soFar = selector;
2180	groups = [];
2181	preFilters = Expr.preFilter;
2182
2183	while ( soFar ) {
2184
2185		// Comma and first run
2186		if ( !matched || (match = rcomma.exec( soFar )) ) {
2187			if ( match ) {
2188				// Don't consume trailing commas as valid
2189				soFar = soFar.slice( match[0].length ) || soFar;
2190			}
2191			groups.push( (tokens = []) );
2192		}
2193
2194		matched = false;
2195
2196		// Combinators
2197		if ( (match = rcombinators.exec( soFar )) ) {
2198			matched = match.shift();
2199			tokens.push({
2200				value: matched,
2201				// Cast descendant combinators to space
2202				type: match[0].replace( rtrim, " " )
2203			});
2204			soFar = soFar.slice( matched.length );
2205		}
2206
2207		// Filters
2208		for ( type in Expr.filter ) {
2209			if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] ||
2210				(match = preFilters[ type ]( match ))) ) {
2211				matched = match.shift();
2212				tokens.push({
2213					value: matched,
2214					type: type,
2215					matches: match
2216				});
2217				soFar = soFar.slice( matched.length );
2218			}
2219		}
2220
2221		if ( !matched ) {
2222			break;
2223		}
2224	}
2225
2226	// Return the length of the invalid excess
2227	// if we're just parsing
2228	// Otherwise, throw an error or return tokens
2229	return parseOnly ?
2230		soFar.length :
2231		soFar ?
2232			Sizzle.error( selector ) :
2233			// Cache the tokens
2234			tokenCache( selector, groups ).slice( 0 );
2235};
2236
2237function toSelector( tokens ) {
2238	var i = 0,
2239		len = tokens.length,
2240		selector = "";
2241	for ( ; i < len; i++ ) {
2242		selector += tokens[i].value;
2243	}
2244	return selector;
2245}
2246
2247function addCombinator( matcher, combinator, base ) {
2248	var dir = combinator.dir,
2249		skip = combinator.next,
2250		key = skip || dir,
2251		checkNonElements = base && key === "parentNode",
2252		doneName = done++;
2253
2254	return combinator.first ?
2255		// Check against closest ancestor/preceding element
2256		function( elem, context, xml ) {
2257			while ( (elem = elem[ dir ]) ) {
2258				if ( elem.nodeType === 1 || checkNonElements ) {
2259					return matcher( elem, context, xml );
2260				}
2261			}
2262			return false;
2263		} :
2264
2265		// Check against all ancestor/preceding elements
2266		function( elem, context, xml ) {
2267			var oldCache, uniqueCache, outerCache,
2268				newCache = [ dirruns, doneName ];
2269
2270			// We can't set arbitrary data on XML nodes, so they don't benefit from combinator caching
2271			if ( xml ) {
2272				while ( (elem = elem[ dir ]) ) {
2273					if ( elem.nodeType === 1 || checkNonElements ) {
2274						if ( matcher( elem, context, xml ) ) {
2275							return true;
2276						}
2277					}
2278				}
2279			} else {
2280				while ( (elem = elem[ dir ]) ) {
2281					if ( elem.nodeType === 1 || checkNonElements ) {
2282						outerCache = elem[ expando ] || (elem[ expando ] = {});
2283
2284						// Support: IE <9 only
2285						// Defend against cloned attroperties (jQuery gh-1709)
2286						uniqueCache = outerCache[ elem.uniqueID ] || (outerCache[ elem.uniqueID ] = {});
2287
2288						if ( skip && skip === elem.nodeName.toLowerCase() ) {
2289							elem = elem[ dir ] || elem;
2290						} else if ( (oldCache = uniqueCache[ key ]) &&
2291							oldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) {
2292
2293							// Assign to newCache so results back-propagate to previous elements
2294							return (newCache[ 2 ] = oldCache[ 2 ]);
2295						} else {
2296							// Reuse newcache so results back-propagate to previous elements
2297							uniqueCache[ key ] = newCache;
2298
2299							// A match means we're done; a fail means we have to keep checking
2300							if ( (newCache[ 2 ] = matcher( elem, context, xml )) ) {
2301								return true;
2302							}
2303						}
2304					}
2305				}
2306			}
2307			return false;
2308		};
2309}
2310
2311function elementMatcher( matchers ) {
2312	return matchers.length > 1 ?
2313		function( elem, context, xml ) {
2314			var i = matchers.length;
2315			while ( i-- ) {
2316				if ( !matchers[i]( elem, context, xml ) ) {
2317					return false;
2318				}
2319			}
2320			return true;
2321		} :
2322		matchers[0];
2323}
2324
2325function multipleContexts( selector, contexts, results ) {
2326	var i = 0,
2327		len = contexts.length;
2328	for ( ; i < len; i++ ) {
2329		Sizzle( selector, contexts[i], results );
2330	}
2331	return results;
2332}
2333
2334function condense( unmatched, map, filter, context, xml ) {
2335	var elem,
2336		newUnmatched = [],
2337		i = 0,
2338		len = unmatched.length,
2339		mapped = map != null;
2340
2341	for ( ; i < len; i++ ) {
2342		if ( (elem = unmatched[i]) ) {
2343			if ( !filter || filter( elem, context, xml ) ) {
2344				newUnmatched.push( elem );
2345				if ( mapped ) {
2346					map.push( i );
2347				}
2348			}
2349		}
2350	}
2351
2352	return newUnmatched;
2353}
2354
2355function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) {
2356	if ( postFilter && !postFilter[ expando ] ) {
2357		postFilter = setMatcher( postFilter );
2358	}
2359	if ( postFinder && !postFinder[ expando ] ) {
2360		postFinder = setMatcher( postFinder, postSelector );
2361	}
2362	return markFunction(function( seed, results, context, xml ) {
2363		var temp, i, elem,
2364			preMap = [],
2365			postMap = [],
2366			preexisting = results.length,
2367
2368			// Get initial elements from seed or context
2369			elems = seed || multipleContexts( selector || "*", context.nodeType ? [ context ] : context, [] ),
2370
2371			// Prefilter to get matcher input, preserving a map for seed-results synchronization
2372			matcherIn = preFilter && ( seed || !selector ) ?
2373				condense( elems, preMap, preFilter, context, xml ) :
2374				elems,
2375
2376			matcherOut = matcher ?
2377				// If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results,
2378				postFinder || ( seed ? preFilter : preexisting || postFilter ) ?
2379
2380					// ...intermediate processing is necessary
2381					[] :
2382
2383					// ...otherwise use results directly
2384					results :
2385				matcherIn;
2386
2387		// Find primary matches
2388		if ( matcher ) {
2389			matcher( matcherIn, matcherOut, context, xml );
2390		}
2391
2392		// Apply postFilter
2393		if ( postFilter ) {
2394			temp = condense( matcherOut, postMap );
2395			postFilter( temp, [], context, xml );
2396
2397			// Un-match failing elements by moving them back to matcherIn
2398			i = temp.length;
2399			while ( i-- ) {
2400				if ( (elem = temp[i]) ) {
2401					matcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem);
2402				}
2403			}
2404		}
2405
2406		if ( seed ) {
2407			if ( postFinder || preFilter ) {
2408				if ( postFinder ) {
2409					// Get the final matcherOut by condensing this intermediate into postFinder contexts
2410					temp = [];
2411					i = matcherOut.length;
2412					while ( i-- ) {
2413						if ( (elem = matcherOut[i]) ) {
2414							// Restore matcherIn since elem is not yet a final match
2415							temp.push( (matcherIn[i] = elem) );
2416						}
2417					}
2418					postFinder( null, (matcherOut = []), temp, xml );
2419				}
2420
2421				// Move matched elements from seed to results to keep them synchronized
2422				i = matcherOut.length;
2423				while ( i-- ) {
2424					if ( (elem = matcherOut[i]) &&
2425						(temp = postFinder ? indexOf( seed, elem ) : preMap[i]) > -1 ) {
2426
2427						seed[temp] = !(results[temp] = elem);
2428					}
2429				}
2430			}
2431
2432		// Add elements to results, through postFinder if defined
2433		} else {
2434			matcherOut = condense(
2435				matcherOut === results ?
2436					matcherOut.splice( preexisting, matcherOut.length ) :
2437					matcherOut
2438			);
2439			if ( postFinder ) {
2440				postFinder( null, results, matcherOut, xml );
2441			} else {
2442				push.apply( results, matcherOut );
2443			}
2444		}
2445	});
2446}
2447
2448function matcherFromTokens( tokens ) {
2449	var checkContext, matcher, j,
2450		len = tokens.length,
2451		leadingRelative = Expr.relative[ tokens[0].type ],
2452		implicitRelative = leadingRelative || Expr.relative[" "],
2453		i = leadingRelative ? 1 : 0,
2454
2455		// The foundational matcher ensures that elements are reachable from top-level context(s)
2456		matchContext = addCombinator( function( elem ) {
2457			return elem === checkContext;
2458		}, implicitRelative, true ),
2459		matchAnyContext = addCombinator( function( elem ) {
2460			return indexOf( checkContext, elem ) > -1;
2461		}, implicitRelative, true ),
2462		matchers = [ function( elem, context, xml ) {
2463			var ret = ( !leadingRelative && ( xml || context !== outermostContext ) ) || (
2464				(checkContext = context).nodeType ?
2465					matchContext( elem, context, xml ) :
2466					matchAnyContext( elem, context, xml ) );
2467			// Avoid hanging onto element (issue #299)
2468			checkContext = null;
2469			return ret;
2470		} ];
2471
2472	for ( ; i < len; i++ ) {
2473		if ( (matcher = Expr.relative[ tokens[i].type ]) ) {
2474			matchers = [ addCombinator(elementMatcher( matchers ), matcher) ];
2475		} else {
2476			matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches );
2477
2478			// Return special upon seeing a positional matcher
2479			if ( matcher[ expando ] ) {
2480				// Find the next relative operator (if any) for proper handling
2481				j = ++i;
2482				for ( ; j < len; j++ ) {
2483					if ( Expr.relative[ tokens[j].type ] ) {
2484						break;
2485					}
2486				}
2487				return setMatcher(
2488					i > 1 && elementMatcher( matchers ),
2489					i > 1 && toSelector(
2490						// If the preceding token was a descendant combinator, insert an implicit any-element `*`
2491						tokens.slice( 0, i - 1 ).concat({ value: tokens[ i - 2 ].type === " " ? "*" : "" })
2492					).replace( rtrim, "$1" ),
2493					matcher,
2494					i < j && matcherFromTokens( tokens.slice( i, j ) ),
2495					j < len && matcherFromTokens( (tokens = tokens.slice( j )) ),
2496					j < len && toSelector( tokens )
2497				);
2498			}
2499			matchers.push( matcher );
2500		}
2501	}
2502
2503	return elementMatcher( matchers );
2504}
2505
2506function matcherFromGroupMatchers( elementMatchers, setMatchers ) {
2507	var bySet = setMatchers.length > 0,
2508		byElement = elementMatchers.length > 0,
2509		superMatcher = function( seed, context, xml, results, outermost ) {
2510			var elem, j, matcher,
2511				matchedCount = 0,
2512				i = "0",
2513				unmatched = seed && [],
2514				setMatched = [],
2515				contextBackup = outermostContext,
2516				// We must always have either seed elements or outermost context
2517				elems = seed || byElement && Expr.find["TAG"]( "*", outermost ),
2518				// Use integer dirruns iff this is the outermost matcher
2519				dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1),
2520				len = elems.length;
2521
2522			if ( outermost ) {
2523				outermostContext = context === document || context || outermost;
2524			}
2525
2526			// Add elements passing elementMatchers directly to results
2527			// Support: IE<9, Safari
2528			// Tolerate NodeList properties (IE: "length"; Safari: <number>) matching elements by id
2529			for ( ; i !== len && (elem = elems[i]) != null; i++ ) {
2530				if ( byElement && elem ) {
2531					j = 0;
2532					if ( !context && elem.ownerDocument !== document ) {
2533						setDocument( elem );
2534						xml = !documentIsHTML;
2535					}
2536					while ( (matcher = elementMatchers[j++]) ) {
2537						if ( matcher( elem, context || document, xml) ) {
2538							results.push( elem );
2539							break;
2540						}
2541					}
2542					if ( outermost ) {
2543						dirruns = dirrunsUnique;
2544					}
2545				}
2546
2547				// Track unmatched elements for set filters
2548				if ( bySet ) {
2549					// They will have gone through all possible matchers
2550					if ( (elem = !matcher && elem) ) {
2551						matchedCount--;
2552					}
2553
2554					// Lengthen the array for every element, matched or not
2555					if ( seed ) {
2556						unmatched.push( elem );
2557					}
2558				}
2559			}
2560
2561			// `i` is now the count of elements visited above, and adding it to `matchedCount`
2562			// makes the latter nonnegative.
2563			matchedCount += i;
2564
2565			// Apply set filters to unmatched elements
2566			// NOTE: This can be skipped if there are no unmatched elements (i.e., `matchedCount`
2567			// equals `i`), unless we didn't visit _any_ elements in the above loop because we have
2568			// no element matchers and no seed.
2569			// Incrementing an initially-string "0" `i` allows `i` to remain a string only in that
2570			// case, which will result in a "00" `matchedCount` that differs from `i` but is also
2571			// numerically zero.
2572			if ( bySet && i !== matchedCount ) {
2573				j = 0;
2574				while ( (matcher = setMatchers[j++]) ) {
2575					matcher( unmatched, setMatched, context, xml );
2576				}
2577
2578				if ( seed ) {
2579					// Reintegrate element matches to eliminate the need for sorting
2580					if ( matchedCount > 0 ) {
2581						while ( i-- ) {
2582							if ( !(unmatched[i] || setMatched[i]) ) {
2583								setMatched[i] = pop.call( results );
2584							}
2585						}
2586					}
2587
2588					// Discard index placeholder values to get only actual matches
2589					setMatched = condense( setMatched );
2590				}
2591
2592				// Add matches to results
2593				push.apply( results, setMatched );
2594
2595				// Seedless set matches succeeding multiple successful matchers stipulate sorting
2596				if ( outermost && !seed && setMatched.length > 0 &&
2597					( matchedCount + setMatchers.length ) > 1 ) {
2598
2599					Sizzle.uniqueSort( results );
2600				}
2601			}
2602
2603			// Override manipulation of globals by nested matchers
2604			if ( outermost ) {
2605				dirruns = dirrunsUnique;
2606				outermostContext = contextBackup;
2607			}
2608
2609			return unmatched;
2610		};
2611
2612	return bySet ?
2613		markFunction( superMatcher ) :
2614		superMatcher;
2615}
2616
2617compile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) {
2618	var i,
2619		setMatchers = [],
2620		elementMatchers = [],
2621		cached = compilerCache[ selector + " " ];
2622
2623	if ( !cached ) {
2624		// Generate a function of recursive functions that can be used to check each element
2625		if ( !match ) {
2626			match = tokenize( selector );
2627		}
2628		i = match.length;
2629		while ( i-- ) {
2630			cached = matcherFromTokens( match[i] );
2631			if ( cached[ expando ] ) {
2632				setMatchers.push( cached );
2633			} else {
2634				elementMatchers.push( cached );
2635			}
2636		}
2637
2638		// Cache the compiled function
2639		cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) );
2640
2641		// Save selector and tokenization
2642		cached.selector = selector;
2643	}
2644	return cached;
2645};
2646
2647/**
2648 * A low-level selection function that works with Sizzle's compiled
2649 *  selector functions
2650 * @param {String|Function} selector A selector or a pre-compiled
2651 *  selector function built with Sizzle.compile
2652 * @param {Element} context
2653 * @param {Array} [results]
2654 * @param {Array} [seed] A set of elements to match against
2655 */
2656select = Sizzle.select = function( selector, context, results, seed ) {
2657	var i, tokens, token, type, find,
2658		compiled = typeof selector === "function" && selector,
2659		match = !seed && tokenize( (selector = compiled.selector || selector) );
2660
2661	results = results || [];
2662
2663	// Try to minimize operations if there is only one selector in the list and no seed
2664	// (the latter of which guarantees us context)
2665	if ( match.length === 1 ) {
2666
2667		// Reduce context if the leading compound selector is an ID
2668		tokens = match[0] = match[0].slice( 0 );
2669		if ( tokens.length > 2 && (token = tokens[0]).type === "ID" &&
2670				context.nodeType === 9 && documentIsHTML && Expr.relative[ tokens[1].type ] ) {
2671
2672			context = ( Expr.find["ID"]( token.matches[0].replace(runescape, funescape), context ) || [] )[0];
2673			if ( !context ) {
2674				return results;
2675
2676			// Precompiled matchers will still verify ancestry, so step up a level
2677			} else if ( compiled ) {
2678				context = context.parentNode;
2679			}
2680
2681			selector = selector.slice( tokens.shift().value.length );
2682		}
2683
2684		// Fetch a seed set for right-to-left matching
2685		i = matchExpr["needsContext"].test( selector ) ? 0 : tokens.length;
2686		while ( i-- ) {
2687			token = tokens[i];
2688
2689			// Abort if we hit a combinator
2690			if ( Expr.relative[ (type = token.type) ] ) {
2691				break;
2692			}
2693			if ( (find = Expr.find[ type ]) ) {
2694				// Search, expanding context for leading sibling combinators
2695				if ( (seed = find(
2696					token.matches[0].replace( runescape, funescape ),
2697					rsibling.test( tokens[0].type ) && testContext( context.parentNode ) || context
2698				)) ) {
2699
2700					// If seed is empty or no tokens remain, we can return early
2701					tokens.splice( i, 1 );
2702					selector = seed.length && toSelector( tokens );
2703					if ( !selector ) {
2704						push.apply( results, seed );
2705						return results;
2706					}
2707
2708					break;
2709				}
2710			}
2711		}
2712	}
2713
2714	// Compile and execute a filtering function if one is not provided
2715	// Provide `match` to avoid retokenization if we modified the selector above
2716	( compiled || compile( selector, match ) )(
2717		seed,
2718		context,
2719		!documentIsHTML,
2720		results,
2721		!context || rsibling.test( selector ) && testContext( context.parentNode ) || context
2722	);
2723	return results;
2724};
2725
2726// One-time assignments
2727
2728// Sort stability
2729support.sortStable = expando.split("").sort( sortOrder ).join("") === expando;
2730
2731// Support: Chrome 14-35+
2732// Always assume duplicates if they aren't passed to the comparison function
2733support.detectDuplicates = !!hasDuplicate;
2734
2735// Initialize against the default document
2736setDocument();
2737
2738// Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27)
2739// Detached nodes confoundingly follow *each other*
2740support.sortDetached = assert(function( el ) {
2741	// Should return 1, but returns 4 (following)
2742	return el.compareDocumentPosition( document.createElement("fieldset") ) & 1;
2743});
2744
2745// Support: IE<8
2746// Prevent attribute/property "interpolation"
2747// https://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx
2748if ( !assert(function( el ) {
2749	el.innerHTML = "<a href='#'></a>";
2750	return el.firstChild.getAttribute("href") === "#" ;
2751}) ) {
2752	addHandle( "type|href|height|width", function( elem, name, isXML ) {
2753		if ( !isXML ) {
2754			return elem.getAttribute( name, name.toLowerCase() === "type" ? 1 : 2 );
2755		}
2756	});
2757}
2758
2759// Support: IE<9
2760// Use defaultValue in place of getAttribute("value")
2761if ( !support.attributes || !assert(function( el ) {
2762	el.innerHTML = "<input/>";
2763	el.firstChild.setAttribute( "value", "" );
2764	return el.firstChild.getAttribute( "value" ) === "";
2765}) ) {
2766	addHandle( "value", function( elem, name, isXML ) {
2767		if ( !isXML && elem.nodeName.toLowerCase() === "input" ) {
2768			return elem.defaultValue;
2769		}
2770	});
2771}
2772
2773// Support: IE<9
2774// Use getAttributeNode to fetch booleans when getAttribute lies
2775if ( !assert(function( el ) {
2776	return el.getAttribute("disabled") == null;
2777}) ) {
2778	addHandle( booleans, function( elem, name, isXML ) {
2779		var val;
2780		if ( !isXML ) {
2781			return elem[ name ] === true ? name.toLowerCase() :
2782					(val = elem.getAttributeNode( name )) && val.specified ?
2783					val.value :
2784				null;
2785		}
2786	});
2787}
2788
2789return Sizzle;
2790
2791})( window );
2792
2793
2794
2795jQuery.find = Sizzle;
2796jQuery.expr = Sizzle.selectors;
2797
2798// Deprecated
2799jQuery.expr[ ":" ] = jQuery.expr.pseudos;
2800jQuery.uniqueSort = jQuery.unique = Sizzle.uniqueSort;
2801jQuery.text = Sizzle.getText;
2802jQuery.isXMLDoc = Sizzle.isXML;
2803jQuery.contains = Sizzle.contains;
2804jQuery.escapeSelector = Sizzle.escape;
2805
2806
2807
2808
2809var dir = function( elem, dir, until ) {
2810	var matched = [],
2811		truncate = until !== undefined;
2812
2813	while ( ( elem = elem[ dir ] ) && elem.nodeType !== 9 ) {
2814		if ( elem.nodeType === 1 ) {
2815			if ( truncate && jQuery( elem ).is( until ) ) {
2816				break;
2817			}
2818			matched.push( elem );
2819		}
2820	}
2821	return matched;
2822};
2823
2824
2825var siblings = function( n, elem ) {
2826	var matched = [];
2827
2828	for ( ; n; n = n.nextSibling ) {
2829		if ( n.nodeType === 1 && n !== elem ) {
2830			matched.push( n );
2831		}
2832	}
2833
2834	return matched;
2835};
2836
2837
2838var rneedsContext = jQuery.expr.match.needsContext;
2839
2840
2841
2842function nodeName( elem, name ) {
2843
2844  return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase();
2845
2846};
2847var rsingleTag = ( /^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i );
2848
2849
2850
vendor: 1,441 bytes, lines 2851-2899
2851var risSimple = /^.[^:#\[\.,]*$/;
2852
2853// Implement the identical functionality for filter and not
2854function winnow( elements, qualifier, not ) {
2855	if ( jQuery.isFunction( qualifier ) ) {
2856		return jQuery.grep( elements, function( elem, i ) {
2857			return !!qualifier.call( elem, i, elem ) !== not;
2858		} );
2859	}
2860
2861	// Single element
2862	if ( qualifier.nodeType ) {
2863		return jQuery.grep( elements, function( elem ) {
2864			return ( elem === qualifier ) !== not;
2865		} );
2866	}
2867
2868	// Arraylike of elements (jQuery, arguments, Array)
2869	if ( typeof qualifier !== "string" ) {
2870		return jQuery.grep( elements, function( elem ) {
2871			return ( indexOf.call( qualifier, elem ) > -1 ) !== not;
2872		} );
2873	}
2874
2875	// Simple selector that can be filtered directly, removing non-Elements
2876	if ( risSimple.test( qualifier ) ) {
2877		return jQuery.filter( qualifier, elements, not );
2878	}
2879
2880	// Complex selector, compare the two sets, removing non-Elements
2881	qualifier = jQuery.filter( qualifier, elements );
2882	return jQuery.grep( elements, function( elem ) {
2883		return ( indexOf.call( qualifier, elem ) > -1 ) !== not && elem.nodeType === 1;
2884	} );
2885}
2886
2887jQuery.filter = function( expr, elems, not ) {
2888	var elem = elems[ 0 ];
2889
2890	if ( not ) {
2891		expr = ":not(" + expr + ")";
2892	}
2893
2894	if ( elems.length === 1 && elem.nodeType === 1 ) {
2895		return jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : [];
2896	}
2897
2898	return jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) {
2899		return elem.nodeType === 1;
vendor: 4,831 bytes, lines 2900-3095
2900	} ) );
2901};
2902
2903jQuery.fn.extend( {
2904	find: function( selector ) {
2905		var i, ret,
2906			len = this.length,
2907			self = this;
2908
2909		if ( typeof selector !== "string" ) {
2910			return this.pushStack( jQuery( selector ).filter( function() {
2911				for ( i = 0; i < len; i++ ) {
2912					if ( jQuery.contains( self[ i ], this ) ) {
2913						return true;
2914					}
2915				}
2916			} ) );
2917		}
2918
2919		ret = this.pushStack( [] );
2920
2921		for ( i = 0; i < len; i++ ) {
2922			jQuery.find( selector, self[ i ], ret );
2923		}
2924
2925		return len > 1 ? jQuery.uniqueSort( ret ) : ret;
2926	},
2927	filter: function( selector ) {
2928		return this.pushStack( winnow( this, selector || [], false ) );
2929	},
2930	not: function( selector ) {
2931		return this.pushStack( winnow( this, selector || [], true ) );
2932	},
2933	is: function( selector ) {
2934		return !!winnow(
2935			this,
2936
2937			// If this is a positional/relative selector, check membership in the returned set
2938			// so $("p:first").is("p:last") won't return true for a doc with two "p".
2939			typeof selector === "string" && rneedsContext.test( selector ) ?
2940				jQuery( selector ) :
2941				selector || [],
2942			false
2943		).length;
2944	}
2945} );
2946
2947
2948// Initialize a jQuery object
2949
2950
2951// A central reference to the root jQuery(document)
2952var rootjQuery,
2953
2954	// A simple way to check for HTML strings
2955	// Prioritize #id over <tag> to avoid XSS via location.hash (#9521)
2956	// Strict HTML recognition (#11290: must start with <)
2957	// Shortcut simple #id case for speed
2958	rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/,
2959
2960	init = jQuery.fn.init = function( selector, context, root ) {
2961		var match, elem;
2962
2963		// HANDLE: $(""), $(null), $(undefined), $(false)
2964		if ( !selector ) {
2965			return this;
2966		}
2967
2968		// Method init() accepts an alternate rootjQuery
2969		// so migrate can support jQuery.sub (gh-2101)
2970		root = root || rootjQuery;
2971
2972		// Handle HTML strings
2973		if ( typeof selector === "string" ) {
2974			if ( selector[ 0 ] === "<" &&
2975				selector[ selector.length - 1 ] === ">" &&
2976				selector.length >= 3 ) {
2977
2978				// Assume that strings that start and end with <> are HTML and skip the regex check
2979				match = [ null, selector, null ];
2980
2981			} else {
2982				match = rquickExpr.exec( selector );
2983			}
2984
2985			// Match html or make sure no context is specified for #id
2986			if ( match && ( match[ 1 ] || !context ) ) {
2987
2988				// HANDLE: $(html) -> $(array)
2989				if ( match[ 1 ] ) {
2990					context = context instanceof jQuery ? context[ 0 ] : context;
2991
2992					// Option to run scripts is true for back-compat
2993					// Intentionally let the error be thrown if parseHTML is not present
2994					jQuery.merge( this, jQuery.parseHTML(
2995						match[ 1 ],
2996						context && context.nodeType ? context.ownerDocument || context : document,
2997						true
2998					) );
2999
3000					// HANDLE: $(html, props)
3001					if ( rsingleTag.test( match[ 1 ] ) && jQuery.isPlainObject( context ) ) {
3002						for ( match in context ) {
3003
3004							// Properties of context are called as methods if possible
3005							if ( jQuery.isFunction( this[ match ] ) ) {
3006								this[ match ]( context[ match ] );
3007
3008							// ...and otherwise set as attributes
3009							} else {
3010								this.attr( match, context[ match ] );
3011							}
3012						}
3013					}
3014
3015					return this;
3016
3017				// HANDLE: $(#id)
3018				} else {
3019					elem = document.getElementById( match[ 2 ] );
3020
3021					if ( elem ) {
3022
3023						// Inject the element directly into the jQuery object
3024						this[ 0 ] = elem;
3025						this.length = 1;
3026					}
3027					return this;
3028				}
3029
3030			// HANDLE: $(expr, $(...))
3031			} else if ( !context || context.jquery ) {
3032				return ( context || root ).find( selector );
3033
3034			// HANDLE: $(expr, context)
3035			// (which is just equivalent to: $(context).find(expr)
3036			} else {
3037				return this.constructor( context ).find( selector );
3038			}
3039
3040		// HANDLE: $(DOMElement)
3041		} else if ( selector.nodeType ) {
3042			this[ 0 ] = selector;
3043			this.length = 1;
3044			return this;
3045
3046		// HANDLE: $(function)
3047		// Shortcut for document ready
3048		} else if ( jQuery.isFunction( selector ) ) {
3049			return root.ready !== undefined ?
3050				root.ready( selector ) :
3051
3052				// Execute immediately if ready is not present
3053				selector( jQuery );
3054		}
3055
3056		return jQuery.makeArray( selector, this );
3057	};
3058
3059// Give the init function the jQuery prototype for later instantiation
3060init.prototype = jQuery.fn;
3061
3062// Initialize central reference
3063rootjQuery = jQuery( document );
3064
3065
3066var rparentsprev = /^(?:parents|prev(?:Until|All))/,
3067
3068	// Methods guaranteed to produce a unique set when starting from a unique set
3069	guaranteedUnique = {
3070		children: true,
3071		contents: true,
3072		next: true,
3073		prev: true
3074	};
3075
3076jQuery.fn.extend( {
3077	has: function( target ) {
3078		var targets = jQuery( target, this ),
3079			l = targets.length;
3080
3081		return this.filter( function() {
3082			var i = 0;
3083			for ( ; i < l; i++ ) {
3084				if ( jQuery.contains( this, targets[ i ] ) ) {
3085					return true;
3086				}
3087			}
3088		} );
3089	},
3090
3091	closest: function( selectors, context ) {
3092		var cur,
3093			i = 0,
3094			l = this.length,
3095			matched = [],
vendor: 6,797 bytes, lines 3096-3363
3096			targets = typeof selectors !== "string" && jQuery( selectors );
3097
3098		// Positional selectors never match, since there's no _selection_ context
3099		if ( !rneedsContext.test( selectors ) ) {
3100			for ( ; i < l; i++ ) {
3101				for ( cur = this[ i ]; cur && cur !== context; cur = cur.parentNode ) {
3102
3103					// Always skip document fragments
3104					if ( cur.nodeType < 11 && ( targets ?
3105						targets.index( cur ) > -1 :
3106
3107						// Don't pass non-elements to Sizzle
3108						cur.nodeType === 1 &&
3109							jQuery.find.matchesSelector( cur, selectors ) ) ) {
3110
3111						matched.push( cur );
3112						break;
3113					}
3114				}
3115			}
3116		}
3117
3118		return this.pushStack( matched.length > 1 ? jQuery.uniqueSort( matched ) : matched );
3119	},
3120
3121	// Determine the position of an element within the set
3122	index: function( elem ) {
3123
3124		// No argument, return index in parent
3125		if ( !elem ) {
3126			return ( this[ 0 ] && this[ 0 ].parentNode ) ? this.first().prevAll().length : -1;
3127		}
3128
3129		// Index in selector
3130		if ( typeof elem === "string" ) {
3131			return indexOf.call( jQuery( elem ), this[ 0 ] );
3132		}
3133
3134		// Locate the position of the desired element
3135		return indexOf.call( this,
3136
3137			// If it receives a jQuery object, the first element is used
3138			elem.jquery ? elem[ 0 ] : elem
3139		);
3140	},
3141
3142	add: function( selector, context ) {
3143		return this.pushStack(
3144			jQuery.uniqueSort(
3145				jQuery.merge( this.get(), jQuery( selector, context ) )
3146			)
3147		);
3148	},
3149
3150	addBack: function( selector ) {
3151		return this.add( selector == null ?
3152			this.prevObject : this.prevObject.filter( selector )
3153		);
3154	}
3155} );
3156
3157function sibling( cur, dir ) {
3158	while ( ( cur = cur[ dir ] ) && cur.nodeType !== 1 ) {}
3159	return cur;
3160}
3161
3162jQuery.each( {
3163	parent: function( elem ) {
3164		var parent = elem.parentNode;
3165		return parent && parent.nodeType !== 11 ? parent : null;
3166	},
3167	parents: function( elem ) {
3168		return dir( elem, "parentNode" );
3169	},
3170	parentsUntil: function( elem, i, until ) {
3171		return dir( elem, "parentNode", until );
3172	},
3173	next: function( elem ) {
3174		return sibling( elem, "nextSibling" );
3175	},
3176	prev: function( elem ) {
3177		return sibling( elem, "previousSibling" );
3178	},
3179	nextAll: function( elem ) {
3180		return dir( elem, "nextSibling" );
3181	},
3182	prevAll: function( elem ) {
3183		return dir( elem, "previousSibling" );
3184	},
3185	nextUntil: function( elem, i, until ) {
3186		return dir( elem, "nextSibling", until );
3187	},
3188	prevUntil: function( elem, i, until ) {
3189		return dir( elem, "previousSibling", until );
3190	},
3191	siblings: function( elem ) {
3192		return siblings( ( elem.parentNode || {} ).firstChild, elem );
3193	},
3194	children: function( elem ) {
3195		return siblings( elem.firstChild );
3196	},
3197	contents: function( elem ) {
3198        if ( nodeName( elem, "iframe" ) ) {
3199            return elem.contentDocument;
3200        }
3201
3202        // Support: IE 9 - 11 only, iOS 7 only, Android Browser <=4.3 only
3203        // Treat the template element as a regular one in browsers that
3204        // don't support it.
3205        if ( nodeName( elem, "template" ) ) {
3206            elem = elem.content || elem;
3207        }
3208
3209        return jQuery.merge( [], elem.childNodes );
3210	}
3211}, function( name, fn ) {
3212	jQuery.fn[ name ] = function( until, selector ) {
3213		var matched = jQuery.map( this, fn, until );
3214
3215		if ( name.slice( -5 ) !== "Until" ) {
3216			selector = until;
3217		}
3218
3219		if ( selector && typeof selector === "string" ) {
3220			matched = jQuery.filter( selector, matched );
3221		}
3222
3223		if ( this.length > 1 ) {
3224
3225			// Remove duplicates
3226			if ( !guaranteedUnique[ name ] ) {
3227				jQuery.uniqueSort( matched );
3228			}
3229
3230			// Reverse order for parents* and prev-derivatives
3231			if ( rparentsprev.test( name ) ) {
3232				matched.reverse();
3233			}
3234		}
3235
3236		return this.pushStack( matched );
3237	};
3238} );
3239var rnothtmlwhite = ( /[^\x20\t\r\n\f]+/g );
3240
3241
3242
3243// Convert String-formatted options into Object-formatted ones
3244function createOptions( options ) {
3245	var object = {};
3246	jQuery.each( options.match( rnothtmlwhite ) || [], function( _, flag ) {
3247		object[ flag ] = true;
3248	} );
3249	return object;
3250}
3251
3252/*
3253 * Create a callback list using the following parameters:
3254 *
3255 *	options: an optional list of space-separated options that will change how
3256 *			the callback list behaves or a more traditional option object
3257 *
3258 * By default a callback list will act like an event callback list and can be
3259 * "fired" multiple times.
3260 *
3261 * Possible options:
3262 *
3263 *	once:			will ensure the callback list can only be fired once (like a Deferred)
3264 *
3265 *	memory:			will keep track of previous values and will call any callback added
3266 *					after the list has been fired right away with the latest "memorized"
3267 *					values (like a Deferred)
3268 *
3269 *	unique:			will ensure a callback can only be added once (no duplicate in the list)
3270 *
3271 *	stopOnFalse:	interrupt callings when a callback returns false
3272 *
3273 */
3274jQuery.Callbacks = function( options ) {
3275
3276	// Convert options from String-formatted to Object-formatted if needed
3277	// (we check in cache first)
3278	options = typeof options === "string" ?
3279		createOptions( options ) :
3280		jQuery.extend( {}, options );
3281
3282	var // Flag to know if list is currently firing
3283		firing,
3284
3285		// Last fire value for non-forgettable lists
3286		memory,
3287
3288		// Flag to know if list was already fired
3289		fired,
3290
3291		// Flag to prevent firing
3292		locked,
3293
3294		// Actual callback list
3295		list = [],
3296
3297		// Queue of execution data for repeatable lists
3298		queue = [],
3299
3300		// Index of currently firing callback (modified by add/remove as needed)
3301		firingIndex = -1,
3302
3303		// Fire callbacks
3304		fire = function() {
3305
3306			// Enforce single-firing
3307			locked = locked || options.once;
3308
3309			// Execute callbacks for all pending executions,
3310			// respecting firingIndex overrides and runtime changes
3311			fired = firing = true;
3312			for ( ; queue.length; firingIndex = -1 ) {
3313				memory = queue.shift();
3314				while ( ++firingIndex < list.length ) {
3315
3316					// Run callback and check for early termination
3317					if ( list[ firingIndex ].apply( memory[ 0 ], memory[ 1 ] ) === false &&
3318						options.stopOnFalse ) {
3319
3320						// Jump to end and forget the data so .add doesn't re-fire
3321						firingIndex = list.length;
3322						memory = false;
3323					}
3324				}
3325			}
3326
3327			// Forget the data if we're done with it
3328			if ( !options.memory ) {
3329				memory = false;
3330			}
3331
3332			firing = false;
3333
3334			// Clean up if we're done firing for good
3335			if ( locked ) {
3336
3337				// Keep an empty list if we have data for future add calls
3338				if ( memory ) {
3339					list = [];
3340
3341				// Otherwise, this object is spent
3342				} else {
3343					list = "";
3344				}
3345			}
3346		},
3347
3348		// Actual Callbacks object
3349		self = {
3350
3351			// Add a callback or a collection of callbacks to the list
3352			add: function() {
3353				if ( list ) {
3354
3355					// If we have memory from a past run, we should fire after adding
3356					if ( memory && !firing ) {
3357						firingIndex = list.length - 1;
3358						queue.push( memory );
3359					}
3360
3361					( function add( args ) {
3362						jQuery.each( args, function( _, arg ) {
3363							if ( 
vendor: 3,423 bytes, lines 3363-3505
3363jQuery.isFunction( arg ) ) {
3364								if ( !options.unique || !self.has( arg ) ) {
3365									list.push( arg );
3366								}
3367							} else if ( arg && arg.length && jQuery.type( arg ) !== "string" ) {
3368
3369								// Inspect recursively
3370								add( arg );
3371							}
3372						} );
3373					} )( arguments );
3374
3375					if ( memory && !firing ) {
3376						fire();
3377					}
3378				}
3379				return this;
3380			},
3381
3382			// Remove a callback from the list
3383			remove: function() {
3384				jQuery.each( arguments, function( _, arg ) {
3385					var index;
3386					while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) {
3387						list.splice( index, 1 );
3388
3389						// Handle firing indexes
3390						if ( index <= firingIndex ) {
3391							firingIndex--;
3392						}
3393					}
3394				} );
3395				return this;
3396			},
3397
3398			// Check if a given callback is in the list.
3399			// If no argument is given, return whether or not list has callbacks attached.
3400			has: function( fn ) {
3401				return fn ?
3402					jQuery.inArray( fn, list ) > -1 :
3403					list.length > 0;
3404			},
3405
3406			// Remove all callbacks from the list
3407			empty: function() {
3408				if ( list ) {
3409					list = [];
3410				}
3411				return this;
3412			},
3413
3414			// Disable .fire and .add
3415			// Abort any current/pending executions
3416			// Clear all callbacks and values
3417			disable: function() {
3418				locked = queue = [];
3419				list = memory = "";
3420				return this;
3421			},
3422			disabled: function() {
3423				return !list;
3424			},
3425
3426			// Disable .fire
3427			// Also disable .add unless we have memory (since it would have no effect)
3428			// Abort any pending executions
3429			lock: function() {
3430				locked = queue = [];
3431				if ( !memory && !firing ) {
3432					list = memory = "";
3433				}
3434				return this;
3435			},
3436			locked: function() {
3437				return !!locked;
3438			},
3439
3440			// Call all callbacks with the given context and arguments
3441			fireWith: function( context, args ) {
3442				if ( !locked ) {
3443					args = args || [];
3444					args = [ context, args.slice ? args.slice() : args ];
3445					queue.push( args );
3446					if ( !firing ) {
3447						fire();
3448					}
3449				}
3450				return this;
3451			},
3452
3453			// Call all the callbacks with the given arguments
3454			fire: function() {
3455				self.fireWith( this, arguments );
3456				return this;
3457			},
3458
3459			// To know if the callbacks have already been called at least once
3460			fired: function() {
3461				return !!fired;
3462			}
3463		};
3464
3465	return self;
3466};
3467
3468
3469function Identity( v ) {
3470	return v;
3471}
3472function Thrower( ex ) {
3473	throw ex;
3474}
3475
3476function adoptValue( value, resolve, reject, noValue ) {
3477	var method;
3478
3479	try {
3480
3481		// Check for promise aspect first to privilege synchronous behavior
3482		if ( value && jQuery.isFunction( ( method = value.promise ) ) ) {
3483			method.call( value ).done( resolve ).fail( reject );
3484
3485		// Other thenables
3486		} else if ( value && jQuery.isFunction( ( method = value.then ) ) ) {
3487			method.call( value, resolve, reject );
3488
3489		// Other non-thenables
3490		} else {
3491
3492			// Control `resolve` arguments by letting Array#slice cast boolean `noValue` to integer:
3493			// * false: [ value ].slice( 0 ) => resolve( value )
3494			// * true: [ value ].slice( 1 ) => resolve()
3495			resolve.apply( undefined, [ value ].slice( noValue ) );
3496		}
3497
3498	// For Promises/A+, convert exceptions into rejections
3499	// Since jQuery.when doesn't unwrap thenables, we can skip the extra checks appearing in
3500	// Deferred#then to conditionally suppress rejection.
3501	} catch ( value ) {
3502
3503		// Support: Android 4.0 only
3504		// Strict mode functions invoked without .call/.apply get global-object context
3505		reject.apply( undefined, [ value ]
vendor: 9,153 bytes, lines 3505-3830
3505 );
3506	}
3507}
3508
3509jQuery.extend( {
3510
3511	Deferred: function( func ) {
3512		var tuples = [
3513
3514				// action, add listener, callbacks,
3515				// ... .then handlers, argument index, [final state]
3516				[ "notify", "progress", jQuery.Callbacks( "memory" ),
3517					jQuery.Callbacks( "memory" ), 2 ],
3518				[ "resolve", "done", jQuery.Callbacks( "once memory" ),
3519					jQuery.Callbacks( "once memory" ), 0, "resolved" ],
3520				[ "reject", "fail", jQuery.Callbacks( "once memory" ),
3521					jQuery.Callbacks( "once memory" ), 1, "rejected" ]
3522			],
3523			state = "pending",
3524			promise = {
3525				state: function() {
3526					return state;
3527				},
3528				always: function() {
3529					deferred.done( arguments ).fail( arguments );
3530					return this;
3531				},
3532				"catch": function( fn ) {
3533					return promise.then( null, fn );
3534				},
3535
3536				// Keep pipe for back-compat
3537				pipe: function( /* fnDone, fnFail, fnProgress */ ) {
3538					var fns = arguments;
3539
3540					return jQuery.Deferred( function( newDefer ) {
3541						jQuery.each( tuples, function( i, tuple ) {
3542
3543							// Map tuples (progress, done, fail) to arguments (done, fail, progress)
3544							var fn = jQuery.isFunction( fns[ tuple[ 4 ] ] ) && fns[ tuple[ 4 ] ];
3545
3546							// deferred.progress(function() { bind to newDefer or newDefer.notify })
3547							// deferred.done(function() { bind to newDefer or newDefer.resolve })
3548							// deferred.fail(function() { bind to newDefer or newDefer.reject })
3549							deferred[ tuple[ 1 ] ]( function() {
3550								var returned = fn && fn.apply( this, arguments );
3551								if ( returned && jQuery.isFunction( returned.promise ) ) {
3552									returned.promise()
3553										.progress( newDefer.notify )
3554										.done( newDefer.resolve )
3555										.fail( newDefer.reject );
3556								} else {
3557									newDefer[ tuple[ 0 ] + "With" ](
3558										this,
3559										fn ? [ returned ] : arguments
3560									);
3561								}
3562							} );
3563						} );
3564						fns = null;
3565					} ).promise();
3566				},
3567				then: function( onFulfilled, onRejected, onProgress ) {
3568					var maxDepth = 0;
3569					function resolve( depth, deferred, handler, special ) {
3570						return function() {
3571							var that = this,
3572								args = arguments,
3573								mightThrow = function() {
3574									var returned, then;
3575
3576									// Support: Promises/A+ section 2.3.3.3.3
3577									// https://promisesaplus.com/#point-59
3578									// Ignore double-resolution attempts
3579									if ( depth < maxDepth ) {
3580										return;
3581									}
3582
3583									returned = handler.apply( that, args );
3584
3585									// Support: Promises/A+ section 2.3.1
3586									// https://promisesaplus.com/#point-48
3587									if ( returned === deferred.promise() ) {
3588										throw new TypeError( "Thenable self-resolution" );
3589									}
3590
3591									// Support: Promises/A+ sections 2.3.3.1, 3.5
3592									// https://promisesaplus.com/#point-54
3593									// https://promisesaplus.com/#point-75
3594									// Retrieve `then` only once
3595									then = returned &&
3596
3597										// Support: Promises/A+ section 2.3.4
3598										// https://promisesaplus.com/#point-64
3599										// Only check objects and functions for thenability
3600										( typeof returned === "object" ||
3601											typeof returned === "function" ) &&
3602										returned.then;
3603
3604									// Handle a returned thenable
3605									if ( jQuery.isFunction( then ) ) {
3606
3607										// Special processors (notify) just wait for resolution
3608										if ( special ) {
3609											then.call(
3610												returned,
3611												resolve( maxDepth, deferred, Identity, special ),
3612												resolve( maxDepth, deferred, Thrower, special )
3613											);
3614
3615										// Normal processors (resolve) also hook into progress
3616										} else {
3617
3618											// ...and disregard older resolution values
3619											maxDepth++;
3620
3621											then.call(
3622												returned,
3623												resolve( maxDepth, deferred, Identity, special ),
3624												resolve( maxDepth, deferred, Thrower, special ),
3625												resolve( maxDepth, deferred, Identity,
3626													deferred.notifyWith )
3627											);
3628										}
3629
3630									// Handle all other returned values
3631									} else {
3632
3633										// Only substitute handlers pass on context
3634										// and multiple values (non-spec behavior)
3635										if ( handler !== Identity ) {
3636											that = undefined;
3637											args = [ returned ];
3638										}
3639
3640										// Process the value(s)
3641										// Default process is resolve
3642										( special || deferred.resolveWith )( that, args );
3643									}
3644								},
3645
3646								// Only normal processors (resolve) catch and reject exceptions
3647								process = special ?
3648									mightThrow :
3649									function() {
3650										try {
3651											mightThrow();
3652										} catch ( e ) {
3653
3654											if ( jQuery.Deferred.exceptionHook ) {
3655												jQuery.Deferred.exceptionHook( e,
3656													process.stackTrace );
3657											}
3658
3659											// Support: Promises/A+ section 2.3.3.3.4.1
3660											// https://promisesaplus.com/#point-61
3661											// Ignore post-resolution exceptions
3662											if ( depth + 1 >= maxDepth ) {
3663
3664												// Only substitute handlers pass on context
3665												// and multiple values (non-spec behavior)
3666												if ( handler !== Thrower ) {
3667													that = undefined;
3668													args = [ e ];
3669												}
3670
3671												deferred.rejectWith( that, args );
3672											}
3673										}
3674									};
3675
3676							// Support: Promises/A+ section 2.3.3.3.1
3677							// https://promisesaplus.com/#point-57
3678							// Re-resolve promises immediately to dodge false rejection from
3679							// subsequent errors
3680							if ( depth ) {
3681								process();
3682							} else {
3683
3684								// Call an optional hook to record the stack, in case of exception
3685								// since it's otherwise lost when execution goes async
3686								if ( jQuery.Deferred.getStackHook ) {
3687									process.stackTrace = jQuery.Deferred.getStackHook();
3688								}
3689								window.setTimeout( process );
3690							}
3691						};
3692					}
3693
3694					return jQuery.Deferred( function( newDefer ) {
3695
3696						// progress_handlers.add( ... )
3697						tuples[ 0 ][ 3 ].add(
3698							resolve(
3699								0,
3700								newDefer,
3701								jQuery.isFunction( onProgress ) ?
3702									onProgress :
3703									Identity,
3704								newDefer.notifyWith
3705							)
3706						);
3707
3708						// fulfilled_handlers.add( ... )
3709						tuples[ 1 ][ 3 ].add(
3710							resolve(
3711								0,
3712								newDefer,
3713								jQuery.isFunction( onFulfilled ) ?
3714									onFulfilled :
3715									Identity
3716							)
3717						);
3718
3719						// rejected_handlers.add( ... )
3720						tuples[ 2 ][ 3 ].add(
3721							resolve(
3722								0,
3723								newDefer,
3724								jQuery.isFunction( onRejected ) ?
3725									onRejected :
3726									Thrower
3727							)
3728						);
3729					} ).promise();
3730				},
3731
3732				// Get a promise for this deferred
3733				// If obj is provided, the promise aspect is added to the object
3734				promise: function( obj ) {
3735					return obj != null ? jQuery.extend( obj, promise ) : promise;
3736				}
3737			},
3738			deferred = {};
3739
3740		// Add list-specific methods
3741		jQuery.each( tuples, function( i, tuple ) {
3742			var list = tuple[ 2 ],
3743				stateString = tuple[ 5 ];
3744
3745			// promise.progress = list.add
3746			// promise.done = list.add
3747			// promise.fail = list.add
3748			promise[ tuple[ 1 ] ] = list.add;
3749
3750			// Handle state
3751			if ( stateString ) {
3752				list.add(
3753					function() {
3754
3755						// state = "resolved" (i.e., fulfilled)
3756						// state = "rejected"
3757						state = stateString;
3758					},
3759
3760					// rejected_callbacks.disable
3761					// fulfilled_callbacks.disable
3762					tuples[ 3 - i ][ 2 ].disable,
3763
3764					// progress_callbacks.lock
3765					tuples[ 0 ][ 2 ].lock
3766				);
3767			}
3768
3769			// progress_handlers.fire
3770			// fulfilled_handlers.fire
3771			// rejected_handlers.fire
3772			list.add( tuple[ 3 ].fire );
3773
3774			// deferred.notify = function() { deferred.notifyWith(...) }
3775			// deferred.resolve = function() { deferred.resolveWith(...) }
3776			// deferred.reject = function() { deferred.rejectWith(...) }
3777			deferred[ tuple[ 0 ] ] = function() {
3778				deferred[ tuple[ 0 ] + "With" ]( this === deferred ? undefined : this, arguments );
3779				return this;
3780			};
3781
3782			// deferred.notifyWith = list.fireWith
3783			// deferred.resolveWith = list.fireWith
3784			// deferred.rejectWith = list.fireWith
3785			deferred[ tuple[ 0 ] + "With" ] = list.fireWith;
3786		} );
3787
3788		// Make the deferred a promise
3789		promise.promise( deferred );
3790
3791		// Call given func if any
3792		if ( func ) {
3793			func.call( deferred, deferred );
3794		}
3795
3796		// All done!
3797		return deferred;
3798	},
3799
3800	// Deferred helper
3801	when: function( singleValue ) {
3802		var
3803
3804			// count of uncompleted subordinates
3805			remaining = arguments.length,
3806
3807			// count of unprocessed arguments
3808			i = remaining,
3809
3810			// subordinate fulfillment data
3811			resolveContexts = Array( i ),
3812			resolveValues = slice.call( arguments ),
3813
3814			// the master Deferred
3815			master = jQuery.Deferred(),
3816
3817			// subordinate callback factory
3818			updateFunc = function( i ) {
3819				return function( value ) {
3820					resolveContexts[ i ] = this;
3821					resolveValues[ i ] = arguments.length > 1 ? slice.call( arguments ) : value;
3822					if ( !( --remaining ) ) {
3823						master.resolveWith( resolveContexts, resolveValues );
3824					}
3825				};
3826			};
3827
3828		// Single- and empty arguments are adopted like Promise.resolve
3829		if ( remaining <= 1 ) {
3830			adoptValue( singleValue, master.done( updateFunc( i ) ).resolve, master.reject
vendor: 2,079 bytes, lines 3830-3918
3830,
3831				!remaining );
3832
3833			// Use .then() to unwrap secondary thenables (cf. gh-3000)
3834			if ( master.state() === "pending" ||
3835				jQuery.isFunction( resolveValues[ i ] && resolveValues[ i ].then ) ) {
3836
3837				return master.then();
3838			}
3839		}
3840
3841		// Multiple arguments are aggregated like Promise.all array elements
3842		while ( i-- ) {
3843			adoptValue( resolveValues[ i ], updateFunc( i ), master.reject );
3844		}
3845
3846		return master.promise();
3847	}
3848} );
3849
3850
3851// These usually indicate a programmer mistake during development,
3852// warn about them ASAP rather than swallowing them by default.
3853var rerrorNames = /^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/;
3854
3855jQuery.Deferred.exceptionHook = function( error, stack ) {
3856
3857	// Support: IE 8 - 9 only
3858	// Console exists when dev tools are open, which can happen at any time
3859	if ( window.console && window.console.warn && error && rerrorNames.test( error.name ) ) {
3860		window.console.warn( "jQuery.Deferred exception: " + error.message, error.stack, stack );
3861	}
3862};
3863
3864
3865
3866
3867jQuery.readyException = function( error ) {
3868	window.setTimeout( function() {
3869		throw error;
3870	} );
3871};
3872
3873
3874
3875
3876// The deferred used on DOM ready
3877var readyList = jQuery.Deferred();
3878
3879jQuery.fn.ready = function( fn ) {
3880
3881	readyList
3882		.then( fn )
3883
3884		// Wrap jQuery.readyException in a function so that the lookup
3885		// happens at the time of error handling instead of callback
3886		// registration.
3887		.catch( function( error ) {
3888			jQuery.readyException( error );
3889		} );
3890
3891	return this;
3892};
3893
3894jQuery.extend( {
3895
3896	// Is the DOM ready to be used? Set to true once it occurs.
3897	isReady: false,
3898
3899	// A counter to track how many items to wait for before
3900	// the ready event fires. See #6781
3901	readyWait: 1,
3902
3903	// Handle when the DOM is ready
3904	ready: function( wait ) {
3905
3906		// Abort if there are pending holds or we're already ready
3907		if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) {
3908			return;
3909		}
3910
3911		// Remember that the DOM is ready
3912		jQuery.isReady = true;
3913
3914		// If a normal DOM Ready event fired, decrement, and wait if need be
3915		if ( wait !== true && --jQuery.readyWait > 0 ) {
3916			return;
3917		}
3918
vendor: 4,098 bytes, lines 3919-4100
3919		// If there are functions bound, to execute
3920		readyList.resolveWith( document, [ jQuery ] );
3921	}
3922} );
3923
3924jQuery.ready.then = readyList.then;
3925
3926// The ready event handler and self cleanup method
3927function completed() {
3928	document.removeEventListener( "DOMContentLoaded", completed );
3929	window.removeEventListener( "load", completed );
3930	jQuery.ready();
3931}
3932
3933// Catch cases where $(document).ready() is called
3934// after the browser event has already occurred.
3935// Support: IE <=9 - 10 only
3936// Older IE sometimes signals "interactive" too soon
3937if ( document.readyState === "complete" ||
3938	( document.readyState !== "loading" && !document.documentElement.doScroll ) ) {
3939
3940	// Handle it asynchronously to allow scripts the opportunity to delay ready
3941	window.setTimeout( jQuery.ready );
3942
3943} else {
3944
3945	// Use the handy event callback
3946	document.addEventListener( "DOMContentLoaded", completed );
3947
3948	// A fallback to window.onload, that will always work
3949	window.addEventListener( "load", completed );
3950}
3951
3952
3953
3954
3955// Multifunctional method to get and set values of a collection
3956// The value/s can optionally be executed if it's a function
3957var access = function( elems, fn, key, value, chainable, emptyGet, raw ) {
3958	var i = 0,
3959		len = elems.length,
3960		bulk = key == null;
3961
3962	// Sets many values
3963	if ( jQuery.type( key ) === "object" ) {
3964		chainable = true;
3965		for ( i in key ) {
3966			access( elems, fn, i, key[ i ], true, emptyGet, raw );
3967		}
3968
3969	// Sets one value
3970	} else if ( value !== undefined ) {
3971		chainable = true;
3972
3973		if ( !jQuery.isFunction( value ) ) {
3974			raw = true;
3975		}
3976
3977		if ( bulk ) {
3978
3979			// Bulk operations run against the entire set
3980			if ( raw ) {
3981				fn.call( elems, value );
3982				fn = null;
3983
3984			// ...except when executing function values
3985			} else {
3986				bulk = fn;
3987				fn = function( elem, key, value ) {
3988					return bulk.call( jQuery( elem ), value );
3989				};
3990			}
3991		}
3992
3993		if ( fn ) {
3994			for ( ; i < len; i++ ) {
3995				fn(
3996					elems[ i ], key, raw ?
3997					value :
3998					value.call( elems[ i ], i, fn( elems[ i ], key ) )
3999				);
4000			}
4001		}
4002	}
4003
4004	if ( chainable ) {
4005		return elems;
4006	}
4007
4008	// Gets
4009	if ( bulk ) {
4010		return fn.call( elems );
4011	}
4012
4013	return len ? fn( elems[ 0 ], key ) : emptyGet;
4014};
4015var acceptData = function( owner ) {
4016
4017	// Accepts only:
4018	//  - Node
4019	//    - Node.ELEMENT_NODE
4020	//    - Node.DOCUMENT_NODE
4021	//  - Object
4022	//    - Any
4023	return owner.nodeType === 1 || owner.nodeType === 9 || !( +owner.nodeType );
4024};
4025
4026
4027
4028
4029function Data() {
4030	this.expando = jQuery.expando + Data.uid++;
4031}
4032
4033Data.uid = 1;
4034
4035Data.prototype = {
4036
4037	cache: function( owner ) {
4038
4039		// Check if the owner object already has a cache
4040		var value = owner[ this.expando ];
4041
4042		// If not, create one
4043		if ( !value ) {
4044			value = {};
4045
4046			// We can accept data for non-element nodes in modern browsers,
4047			// but we should not, see #8335.
4048			// Always return an empty object.
4049			if ( acceptData( owner ) ) {
4050
4051				// If it is a node unlikely to be stringify-ed or looped over
4052				// use plain assignment
4053				if ( owner.nodeType ) {
4054					owner[ this.expando ] = value;
4055
4056				// Otherwise secure it in a non-enumerable property
4057				// configurable must be true to allow the property to be
4058				// deleted when data is removed
4059				} else {
4060					Object.defineProperty( owner, this.expando, {
4061						value: value,
4062						configurable: true
4063					} );
4064				}
4065			}
4066		}
4067
4068		return value;
4069	},
4070	set: function( owner, data, value ) {
4071		var prop,
4072			cache = this.cache( owner );
4073
4074		// Handle: [ owner, key, value ] args
4075		// Always use camelCase key (gh-2257)
4076		if ( typeof data === "string" ) {
4077			cache[ jQuery.camelCase( data ) ] = value;
4078
4079		// Handle: [ owner, { properties } ] args
4080		} else {
4081
4082			// Copy the properties one-by-one to the cache object
4083			for ( prop in data ) {
4084				cache[ jQuery.camelCase( prop ) ] = data[ prop ];
4085			}
4086		}
4087		return cache;
4088	},
4089	get: function( owner, key ) {
4090		return key === undefined ?
4091			this.cache( owner ) :
4092
4093			// Always use camelCase key (gh-2257)
4094			owner[ this.expando ] && owner[ this.expando ][ jQuery.camelCase( key ) ];
4095	},
4096	access: function( owner, key, value ) {
4097
4098		// In cases where either:
4099		//
4100		//   1. No key was specified
vendor: 4,593 bytes, lines 4101-4284
4101		//   2. A string key was specified, but no value provided
4102		//
4103		// Take the "read" path and allow the get method to determine
4104		// which value to return, respectively either:
4105		//
4106		//   1. The entire cache object
4107		//   2. The data stored at the key
4108		//
4109		if ( key === undefined ||
4110				( ( key && typeof key === "string" ) && value === undefined ) ) {
4111
4112			return this.get( owner, key );
4113		}
4114
4115		// When the key is not a string, or both a key and value
4116		// are specified, set or extend (existing objects) with either:
4117		//
4118		//   1. An object of properties
4119		//   2. A key and value
4120		//
4121		this.set( owner, key, value );
4122
4123		// Since the "set" path can have two possible entry points
4124		// return the expected data based on which path was taken[*]
4125		return value !== undefined ? value : key;
4126	},
4127	remove: function( owner, key ) {
4128		var i,
4129			cache = owner[ this.expando ];
4130
4131		if ( cache === undefined ) {
4132			return;
4133		}
4134
4135		if ( key !== undefined ) {
4136
4137			// Support array or space separated string of keys
4138			if ( Array.isArray( key ) ) {
4139
4140				// If key is an array of keys...
4141				// We always set camelCase keys, so remove that.
4142				key = key.map( jQuery.camelCase );
4143			} else {
4144				key = jQuery.camelCase( key );
4145
4146				// If a key with the spaces exists, use it.
4147				// Otherwise, create an array by matching non-whitespace
4148				key = key in cache ?
4149					[ key ] :
4150					( key.match( rnothtmlwhite ) || [] );
4151			}
4152
4153			i = key.length;
4154
4155			while ( i-- ) {
4156				delete cache[ key[ i ] ];
4157			}
4158		}
4159
4160		// Remove the expando if there's no more data
4161		if ( key === undefined || jQuery.isEmptyObject( cache ) ) {
4162
4163			// Support: Chrome <=35 - 45
4164			// Webkit & Blink performance suffers when deleting properties
4165			// from DOM nodes, so set to undefined instead
4166			// https://bugs.chromium.org/p/chromium/issues/detail?id=378607 (bug restricted)
4167			if ( owner.nodeType ) {
4168				owner[ this.expando ] = undefined;
4169			} else {
4170				delete owner[ this.expando ];
4171			}
4172		}
4173	},
4174	hasData: function( owner ) {
4175		var cache = owner[ this.expando ];
4176		return cache !== undefined && !jQuery.isEmptyObject( cache );
4177	}
4178};
4179var dataPriv = new Data();
4180
4181var dataUser = new Data();
4182
4183
4184
4185//	Implementation Summary
4186//
4187//	1. Enforce API surface and semantic compatibility with 1.9.x branch
4188//	2. Improve the module's maintainability by reducing the storage
4189//		paths to a single mechanism.
4190//	3. Use the same single mechanism to support "private" and "user" data.
4191//	4. _Never_ expose "private" data to user code (TODO: Drop _data, _removeData)
4192//	5. Avoid exposing implementation details on user objects (eg. expando properties)
4193//	6. Provide a clear path for implementation upgrade to WeakMap in 2014
4194
4195var rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,
4196	rmultiDash = /[A-Z]/g;
4197
4198function getData( data ) {
4199	if ( data === "true" ) {
4200		return true;
4201	}
4202
4203	if ( data === "false" ) {
4204		return false;
4205	}
4206
4207	if ( data === "null" ) {
4208		return null;
4209	}
4210
4211	// Only convert to a number if it doesn't change the string
4212	if ( data === +data + "" ) {
4213		return +data;
4214	}
4215
4216	if ( rbrace.test( data ) ) {
4217		return JSON.parse( data );
4218	}
4219
4220	return data;
4221}
4222
4223function dataAttr( elem, key, data ) {
4224	var name;
4225
4226	// If nothing was found internally, try to fetch any
4227	// data from the HTML5 data-* attribute
4228	if ( data === undefined && elem.nodeType === 1 ) {
4229		name = "data-" + key.replace( rmultiDash, "-$&" ).toLowerCase();
4230		data = elem.getAttribute( name );
4231
4232		if ( typeof data === "string" ) {
4233			try {
4234				data = getData( data );
4235			} catch ( e ) {}
4236
4237			// Make sure we set the data so it isn't changed later
4238			dataUser.set( elem, key, data );
4239		} else {
4240			data = undefined;
4241		}
4242	}
4243	return data;
4244}
4245
4246jQuery.extend( {
4247	hasData: function( elem ) {
4248		return dataUser.hasData( elem ) || dataPriv.hasData( elem );
4249	},
4250
4251	data: function( elem, name, data ) {
4252		return dataUser.access( elem, name, data );
4253	},
4254
4255	removeData: function( elem, name ) {
4256		dataUser.remove( elem, name );
4257	},
4258
4259	// TODO: Now that all calls to _data and _removeData have been replaced
4260	// with direct calls to dataPriv methods, these can be deprecated.
4261	_data: function( elem, name, data ) {
4262		return dataPriv.access( elem, name, data );
4263	},
4264
4265	_removeData: function( elem, name ) {
4266		dataPriv.remove( elem, name );
4267	}
4268} );
4269
4270jQuery.fn.extend( {
4271	data: function( key, value ) {
4272		var i, name, data,
4273			elem = this[ 0 ],
4274			attrs = elem && elem.attributes;
4275
4276		// Gets all values
4277		if ( key === undefined ) {
4278			if ( this.length ) {
4279				data = dataUser.get( elem );
4280
4281				if ( elem.nodeType === 1 && !dataPriv.get( elem, "hasDataAttrs" ) ) {
4282					i = attrs.length;
4283					while ( i-- ) {
4284
vendor: 7,789 bytes, lines 4285-4607
4285						// Support: IE 11 only
4286						// The attrs elements can be null (#14894)
4287						if ( attrs[ i ] ) {
4288							name = attrs[ i ].name;
4289							if ( name.indexOf( "data-" ) === 0 ) {
4290								name = jQuery.camelCase( name.slice( 5 ) );
4291								dataAttr( elem, name, data[ name ] );
4292							}
4293						}
4294					}
4295					dataPriv.set( elem, "hasDataAttrs", true );
4296				}
4297			}
4298
4299			return data;
4300		}
4301
4302		// Sets multiple values
4303		if ( typeof key === "object" ) {
4304			return this.each( function() {
4305				dataUser.set( this, key );
4306			} );
4307		}
4308
4309		return access( this, function( value ) {
4310			var data;
4311
4312			// The calling jQuery object (element matches) is not empty
4313			// (and therefore has an element appears at this[ 0 ]) and the
4314			// `value` parameter was not undefined. An empty jQuery object
4315			// will result in `undefined` for elem = this[ 0 ] which will
4316			// throw an exception if an attempt to read a data cache is made.
4317			if ( elem && value === undefined ) {
4318
4319				// Attempt to get data from the cache
4320				// The key will always be camelCased in Data
4321				data = dataUser.get( elem, key );
4322				if ( data !== undefined ) {
4323					return data;
4324				}
4325
4326				// Attempt to "discover" the data in
4327				// HTML5 custom data-* attrs
4328				data = dataAttr( elem, key );
4329				if ( data !== undefined ) {
4330					return data;
4331				}
4332
4333				// We tried really hard, but the data doesn't exist.
4334				return;
4335			}
4336
4337			// Set the data...
4338			this.each( function() {
4339
4340				// We always store the camelCased key
4341				dataUser.set( this, key, value );
4342			} );
4343		}, null, value, arguments.length > 1, null, true );
4344	},
4345
4346	removeData: function( key ) {
4347		return this.each( function() {
4348			dataUser.remove( this, key );
4349		} );
4350	}
4351} );
4352
4353
4354jQuery.extend( {
4355	queue: function( elem, type, data ) {
4356		var queue;
4357
4358		if ( elem ) {
4359			type = ( type || "fx" ) + "queue";
4360			queue = dataPriv.get( elem, type );
4361
4362			// Speed up dequeue by getting out quickly if this is just a lookup
4363			if ( data ) {
4364				if ( !queue || Array.isArray( data ) ) {
4365					queue = dataPriv.access( elem, type, jQuery.makeArray( data ) );
4366				} else {
4367					queue.push( data );
4368				}
4369			}
4370			return queue || [];
4371		}
4372	},
4373
4374	dequeue: function( elem, type ) {
4375		type = type || "fx";
4376
4377		var queue = jQuery.queue( elem, type ),
4378			startLength = queue.length,
4379			fn = queue.shift(),
4380			hooks = jQuery._queueHooks( elem, type ),
4381			next = function() {
4382				jQuery.dequeue( elem, type );
4383			};
4384
4385		// If the fx queue is dequeued, always remove the progress sentinel
4386		if ( fn === "inprogress" ) {
4387			fn = queue.shift();
4388			startLength--;
4389		}
4390
4391		if ( fn ) {
4392
4393			// Add a progress sentinel to prevent the fx queue from being
4394			// automatically dequeued
4395			if ( type === "fx" ) {
4396				queue.unshift( "inprogress" );
4397			}
4398
4399			// Clear up the last queue stop function
4400			delete hooks.stop;
4401			fn.call( elem, next, hooks );
4402		}
4403
4404		if ( !startLength && hooks ) {
4405			hooks.empty.fire();
4406		}
4407	},
4408
4409	// Not public - generate a queueHooks object, or return the current one
4410	_queueHooks: function( elem, type ) {
4411		var key = type + "queueHooks";
4412		return dataPriv.get( elem, key ) || dataPriv.access( elem, key, {
4413			empty: jQuery.Callbacks( "once memory" ).add( function() {
4414				dataPriv.remove( elem, [ type + "queue", key ] );
4415			} )
4416		} );
4417	}
4418} );
4419
4420jQuery.fn.extend( {
4421	queue: function( type, data ) {
4422		var setter = 2;
4423
4424		if ( typeof type !== "string" ) {
4425			data = type;
4426			type = "fx";
4427			setter--;
4428		}
4429
4430		if ( arguments.length < setter ) {
4431			return jQuery.queue( this[ 0 ], type );
4432		}
4433
4434		return data === undefined ?
4435			this :
4436			this.each( function() {
4437				var queue = jQuery.queue( this, type, data );
4438
4439				// Ensure a hooks for this queue
4440				jQuery._queueHooks( this, type );
4441
4442				if ( type === "fx" && queue[ 0 ] !== "inprogress" ) {
4443					jQuery.dequeue( this, type );
4444				}
4445			} );
4446	},
4447	dequeue: function( type ) {
4448		return this.each( function() {
4449			jQuery.dequeue( this, type );
4450		} );
4451	},
4452	clearQueue: function( type ) {
4453		return this.queue( type || "fx", [] );
4454	},
4455
4456	// Get a promise resolved when queues of a certain type
4457	// are emptied (fx is the type by default)
4458	promise: function( type, obj ) {
4459		var tmp,
4460			count = 1,
4461			defer = jQuery.Deferred(),
4462			elements = this,
4463			i = this.length,
4464			resolve = function() {
4465				if ( !( --count ) ) {
4466					defer.resolveWith( elements, [ elements ] );
4467				}
4468			};
4469
4470		if ( typeof type !== "string" ) {
4471			obj = type;
4472			type = undefined;
4473		}
4474		type = type || "fx";
4475
4476		while ( i-- ) {
4477			tmp = dataPriv.get( elements[ i ], type + "queueHooks" );
4478			if ( tmp && tmp.empty ) {
4479				count++;
4480				tmp.empty.add( resolve );
4481			}
4482		}
4483		resolve();
4484		return defer.promise( obj );
4485	}
4486} );
4487var pnum = ( /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/ ).source;
4488
4489var rcssNum = new RegExp( "^(?:([+-])=|)(" + pnum + ")([a-z%]*)$", "i" );
4490
4491
4492var cssExpand = [ "Top", "Right", "Bottom", "Left" ];
4493
4494var isHiddenWithinTree = function( elem, el ) {
4495
4496		// isHiddenWithinTree might be called from jQuery#filter function;
4497		// in that case, element will be second argument
4498		elem = el || elem;
4499
4500		// Inline style trumps all
4501		return elem.style.display === "none" ||
4502			elem.style.display === "" &&
4503
4504			// Otherwise, check computed style
4505			// Support: Firefox <=43 - 45
4506			// Disconnected elements can have computed display: none, so first confirm that elem is
4507			// in the document.
4508			jQuery.contains( elem.ownerDocument, elem ) &&
4509
4510			jQuery.css( elem, "display" ) === "none";
4511	};
4512
4513var swap = function( elem, options, callback, args ) {
4514	var ret, name,
4515		old = {};
4516
4517	// Remember the old values, and insert the new ones
4518	for ( name in options ) {
4519		old[ name ] = elem.style[ name ];
4520		elem.style[ name ] = options[ name ];
4521	}
4522
4523	ret = callback.apply( elem, args || [] );
4524
4525	// Revert the old values
4526	for ( name in options ) {
4527		elem.style[ name ] = old[ name ];
4528	}
4529
4530	return ret;
4531};
4532
4533
4534
4535
4536function adjustCSS( elem, prop, valueParts, tween ) {
4537	var adjusted,
4538		scale = 1,
4539		maxIterations = 20,
4540		currentValue = tween ?
4541			function() {
4542				return tween.cur();
4543			} :
4544			function() {
4545				return jQuery.css( elem, prop, "" );
4546			},
4547		initial = currentValue(),
4548		unit = valueParts && valueParts[ 3 ] || ( jQuery.cssNumber[ prop ] ? "" : "px" ),
4549
4550		// Starting value computation is required for potential unit mismatches
4551		initialInUnit = ( jQuery.cssNumber[ prop ] || unit !== "px" && +initial ) &&
4552			rcssNum.exec( jQuery.css( elem, prop ) );
4553
4554	if ( initialInUnit && initialInUnit[ 3 ] !== unit ) {
4555
4556		// Trust units reported by jQuery.css
4557		unit = unit || initialInUnit[ 3 ];
4558
4559		// Make sure we update the tween properties later on
4560		valueParts = valueParts || [];
4561
4562		// Iteratively approximate from a nonzero starting point
4563		initialInUnit = +initial || 1;
4564
4565		do {
4566
4567			// If previous iteration zeroed out, double until we get *something*.
4568			// Use string for doubling so we don't accidentally see scale as unchanged below
4569			scale = scale || ".5";
4570
4571			// Adjust and apply
4572			initialInUnit = initialInUnit / scale;
4573			jQuery.style( elem, prop, initialInUnit + unit );
4574
4575		// Update scale, tolerating zero or NaN from tween.cur()
4576		// Break the loop if scale is unchanged or perfect, or if we've just had enough.
4577		} while (
4578			scale !== ( scale = currentValue() / initial ) && scale !== 1 && --maxIterations
4579		);
4580	}
4581
4582	if ( valueParts ) {
4583		initialInUnit = +initialInUnit || +initial || 0;
4584
4585		// Apply relative offset (+=/-=) if specified
4586		adjusted = valueParts[ 1 ] ?
4587			initialInUnit + ( valueParts[ 1 ] + 1 ) * valueParts[ 2 ] :
4588			+valueParts[ 2 ];
4589		if ( tween ) {
4590			tween.unit = unit;
4591			tween.start = initialInUnit;
4592			tween.end = adjusted;
4593		}
4594	}
4595	return adjusted;
4596}
4597
4598
4599var defaultDisplayMap = {};
4600
4601function getDefaultDisplay( elem ) {
4602	var temp,
4603		doc = elem.ownerDocument,
4604		nodeName = elem.nodeName,
4605		display = defaultDisplayMap[ nodeName ];
4606
4607	if ( display ) {
vendor: 4,001 bytes, lines 4608-4779
4608		return display;
4609	}
4610
4611	temp = doc.body.appendChild( doc.createElement( nodeName ) );
4612	display = jQuery.css( temp, "display" );
4613
4614	temp.parentNode.removeChild( temp );
4615
4616	if ( display === "none" ) {
4617		display = "block";
4618	}
4619	defaultDisplayMap[ nodeName ] = display;
4620
4621	return display;
4622}
4623
4624function showHide( elements, show ) {
4625	var display, elem,
4626		values = [],
4627		index = 0,
4628		length = elements.length;
4629
4630	// Determine new display value for elements that need to change
4631	for ( ; index < length; index++ ) {
4632		elem = elements[ index ];
4633		if ( !elem.style ) {
4634			continue;
4635		}
4636
4637		display = elem.style.display;
4638		if ( show ) {
4639
4640			// Since we force visibility upon cascade-hidden elements, an immediate (and slow)
4641			// check is required in this first loop unless we have a nonempty display value (either
4642			// inline or about-to-be-restored)
4643			if ( display === "none" ) {
4644				values[ index ] = dataPriv.get( elem, "display" ) || null;
4645				if ( !values[ index ] ) {
4646					elem.style.display = "";
4647				}
4648			}
4649			if ( elem.style.display === "" && isHiddenWithinTree( elem ) ) {
4650				values[ index ] = getDefaultDisplay( elem );
4651			}
4652		} else {
4653			if ( display !== "none" ) {
4654				values[ index ] = "none";
4655
4656				// Remember what we're overwriting
4657				dataPriv.set( elem, "display", display );
4658			}
4659		}
4660	}
4661
4662	// Set the display of the elements in a second loop to avoid constant reflow
4663	for ( index = 0; index < length; index++ ) {
4664		if ( values[ index ] != null ) {
4665			elements[ index ].style.display = values[ index ];
4666		}
4667	}
4668
4669	return elements;
4670}
4671
4672jQuery.fn.extend( {
4673	show: function() {
4674		return showHide( this, true );
4675	},
4676	hide: function() {
4677		return showHide( this );
4678	},
4679	toggle: function( state ) {
4680		if ( typeof state === "boolean" ) {
4681			return state ? this.show() : this.hide();
4682		}
4683
4684		return this.each( function() {
4685			if ( isHiddenWithinTree( this ) ) {
4686				jQuery( this ).show();
4687			} else {
4688				jQuery( this ).hide();
4689			}
4690		} );
4691	}
4692} );
4693var rcheckableType = ( /^(?:checkbox|radio)$/i );
4694
4695var rtagName = ( /<([a-z][^\/\0>\x20\t\r\n\f]+)/i );
4696
4697var rscriptType = ( /^$|\/(?:java|ecma)script/i );
4698
4699
4700
4701// We have to close these tags to support XHTML (#13200)
4702var wrapMap = {
4703
4704	// Support: IE <=9 only
4705	option: [ 1, "<select multiple='multiple'>", "</select>" ],
4706
4707	// XHTML parsers do not magically insert elements in the
4708	// same way that tag soup parsers do. So we cannot shorten
4709	// this by omitting <tbody> or other required elements.
4710	thead: [ 1, "<table>", "</table>" ],
4711	col: [ 2, "<table><colgroup>", "</colgroup></table>" ],
4712	tr: [ 2, "<table><tbody>", "</tbody></table>" ],
4713	td: [ 3, "<table><tbody><tr>", "</tr></tbody></table>" ],
4714
4715	_default: [ 0, "", "" ]
4716};
4717
4718// Support: IE <=9 only
4719wrapMap.optgroup = wrapMap.option;
4720
4721wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
4722wrapMap.th = wrapMap.td;
4723
4724
4725function getAll( context, tag ) {
4726
4727	// Support: IE <=9 - 11 only
4728	// Use typeof to avoid zero-argument method invocation on host objects (#15151)
4729	var ret;
4730
4731	if ( typeof context.getElementsByTagName !== "undefined" ) {
4732		ret = context.getElementsByTagName( tag || "*" );
4733
4734	} else if ( typeof context.querySelectorAll !== "undefined" ) {
4735		ret = context.querySelectorAll( tag || "*" );
4736
4737	} else {
4738		ret = [];
4739	}
4740
4741	if ( tag === undefined || tag && nodeName( context, tag ) ) {
4742		return jQuery.merge( [ context ], ret );
4743	}
4744
4745	return ret;
4746}
4747
4748
4749// Mark scripts as having already been evaluated
4750function setGlobalEval( elems, refElements ) {
4751	var i = 0,
4752		l = elems.length;
4753
4754	for ( ; i < l; i++ ) {
4755		dataPriv.set(
4756			elems[ i ],
4757			"globalEval",
4758			!refElements || dataPriv.get( refElements[ i ], "globalEval" )
4759		);
4760	}
4761}
4762
4763
4764var rhtml = /<|&#?\w+;/;
4765
4766function buildFragment( elems, context, scripts, selection, ignored ) {
4767	var elem, tmp, tag, wrap, contains, j,
4768		fragment = context.createDocumentFragment(),
4769		nodes = [],
4770		i = 0,
4771		l = elems.length;
4772
4773	for ( ; i < l; i++ ) {
4774		elem = elems[ i ];
4775
4776		if ( elem || elem === 0 ) {
4777
4778			// Add nodes directly
4779			if ( jQuery.t
vendor: 14,415 bytes, lines 4779-5289
4779ype( elem ) === "object" ) {
4780
4781				// Support: Android <=4.0 only, PhantomJS 1 only
4782				// push.apply(_, arraylike) throws on ancient WebKit
4783				jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem );
4784
4785			// Convert non-html into a text node
4786			} else if ( !rhtml.test( elem ) ) {
4787				nodes.push( context.createTextNode( elem ) );
4788
4789			// Convert html into DOM nodes
4790			} else {
4791				tmp = tmp || fragment.appendChild( context.createElement( "div" ) );
4792
4793				// Deserialize a standard representation
4794				tag = ( rtagName.exec( elem ) || [ "", "" ] )[ 1 ].toLowerCase();
4795				wrap = wrapMap[ tag ] || wrapMap._default;
4796				tmp.innerHTML = wrap[ 1 ] + jQuery.htmlPrefilter( elem ) + wrap[ 2 ];
4797
4798				// Descend through wrappers to the right content
4799				j = wrap[ 0 ];
4800				while ( j-- ) {
4801					tmp = tmp.lastChild;
4802				}
4803
4804				// Support: Android <=4.0 only, PhantomJS 1 only
4805				// push.apply(_, arraylike) throws on ancient WebKit
4806				jQuery.merge( nodes, tmp.childNodes );
4807
4808				// Remember the top-level container
4809				tmp = fragment.firstChild;
4810
4811				// Ensure the created nodes are orphaned (#12392)
4812				tmp.textContent = "";
4813			}
4814		}
4815	}
4816
4817	// Remove wrapper from fragment
4818	fragment.textContent = "";
4819
4820	i = 0;
4821	while ( ( elem = nodes[ i++ ] ) ) {
4822
4823		// Skip elements already in the context collection (trac-4087)
4824		if ( selection && jQuery.inArray( elem, selection ) > -1 ) {
4825			if ( ignored ) {
4826				ignored.push( elem );
4827			}
4828			continue;
4829		}
4830
4831		contains = jQuery.contains( elem.ownerDocument, elem );
4832
4833		// Append to fragment
4834		tmp = getAll( fragment.appendChild( elem ), "script" );
4835
4836		// Preserve script evaluation history
4837		if ( contains ) {
4838			setGlobalEval( tmp );
4839		}
4840
4841		// Capture executables
4842		if ( scripts ) {
4843			j = 0;
4844			while ( ( elem = tmp[ j++ ] ) ) {
4845				if ( rscriptType.test( elem.type || "" ) ) {
4846					scripts.push( elem );
4847				}
4848			}
4849		}
4850	}
4851
4852	return fragment;
4853}
4854
4855
4856( function() {
4857	var fragment = document.createDocumentFragment(),
4858		div = fragment.appendChild( document.createElement( "div" ) ),
4859		input = document.createElement( "input" );
4860
4861	// Support: Android 4.0 - 4.3 only
4862	// Check state lost if the name is set (#11217)
4863	// Support: Windows Web Apps (WWA)
4864	// `name` and `type` must use .setAttribute for WWA (#14901)
4865	input.setAttribute( "type", "radio" );
4866	input.setAttribute( "checked", "checked" );
4867	input.setAttribute( "name", "t" );
4868
4869	div.appendChild( input );
4870
4871	// Support: Android <=4.1 only
4872	// Older WebKit doesn't clone checked state correctly in fragments
4873	support.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked;
4874
4875	// Support: IE <=11 only
4876	// Make sure textarea (and checkbox) defaultValue is properly cloned
4877	div.innerHTML = "<textarea>x</textarea>";
4878	support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue;
4879} )();
4880var documentElement = document.documentElement;
4881
4882
4883
4884var
4885	rkeyEvent = /^key/,
4886	rmouseEvent = /^(?:mouse|pointer|contextmenu|drag|drop)|click/,
4887	rtypenamespace = /^([^.]*)(?:\.(.+)|)/;
4888
4889function returnTrue() {
4890	return true;
4891}
4892
4893function returnFalse() {
4894	return false;
4895}
4896
4897// Support: IE <=9 only
4898// See #13393 for more info
4899function safeActiveElement() {
4900	try {
4901		return document.activeElement;
4902	} catch ( err ) { }
4903}
4904
4905function on( elem, types, selector, data, fn, one ) {
4906	var origFn, type;
4907
4908	// Types can be a map of types/handlers
4909	if ( typeof types === "object" ) {
4910
4911		// ( types-Object, selector, data )
4912		if ( typeof selector !== "string" ) {
4913
4914			// ( types-Object, data )
4915			data = data || selector;
4916			selector = undefined;
4917		}
4918		for ( type in types ) {
4919			on( elem, type, selector, data, types[ type ], one );
4920		}
4921		return elem;
4922	}
4923
4924	if ( data == null && fn == null ) {
4925
4926		// ( types, fn )
4927		fn = selector;
4928		data = selector = undefined;
4929	} else if ( fn == null ) {
4930		if ( typeof selector === "string" ) {
4931
4932			// ( types, selector, fn )
4933			fn = data;
4934			data = undefined;
4935		} else {
4936
4937			// ( types, data, fn )
4938			fn = data;
4939			data = selector;
4940			selector = undefined;
4941		}
4942	}
4943	if ( fn === false ) {
4944		fn = returnFalse;
4945	} else if ( !fn ) {
4946		return elem;
4947	}
4948
4949	if ( one === 1 ) {
4950		origFn = fn;
4951		fn = function( event ) {
4952
4953			// Can use an empty set, since event contains the info
4954			jQuery().off( event );
4955			return origFn.apply( this, arguments );
4956		};
4957
4958		// Use same guid so caller can remove using origFn
4959		fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ );
4960	}
4961	return elem.each( function() {
4962		jQuery.event.add( this, types, fn, data, selector );
4963	} );
4964}
4965
4966/*
4967 * Helper functions for managing events -- not part of the public interface.
4968 * Props to Dean Edwards' addEvent library for many of the ideas.
4969 */
4970jQuery.event = {
4971
4972	global: {},
4973
4974	add: function( elem, types, handler, data, selector ) {
4975
4976		var handleObjIn, eventHandle, tmp,
4977			events, t, handleObj,
4978			special, handlers, type, namespaces, origType,
4979			elemData = dataPriv.get( elem );
4980
4981		// Don't attach events to noData or text/comment nodes (but allow plain objects)
4982		if ( !elemData ) {
4983			return;
4984		}
4985
4986		// Caller can pass in an object of custom data in lieu of the handler
4987		if ( handler.handler ) {
4988			handleObjIn = handler;
4989			handler = handleObjIn.handler;
4990			selector = handleObjIn.selector;
4991		}
4992
4993		// Ensure that invalid selectors throw exceptions at attach time
4994		// Evaluate against documentElement in case elem is a non-element node (e.g., document)
4995		if ( selector ) {
4996			jQuery.find.matchesSelector( documentElement, selector );
4997		}
4998
4999		// Make sure that the handler has a unique ID, used to find/remove it later
5000		if ( !handler.guid ) {
5001			handler.guid = jQuery.guid++;
5002		}
5003
5004		// Init the element's event structure and main handler, if this is the first
5005		if ( !( events = elemData.events ) ) {
5006			events = elemData.events = {};
5007		}
5008		if ( !( eventHandle = elemData.handle ) ) {
5009			eventHandle = elemData.handle = function( e ) {
5010
5011				// Discard the second event of a jQuery.event.trigger() and
5012				// when an event is called after a page has unloaded
5013				return typeof jQuery !== "undefined" && jQuery.event.triggered !== e.type ?
5014					jQuery.event.dispatch.apply( elem, arguments ) : undefined;
5015			};
5016		}
5017
5018		// Handle multiple events separated by a space
5019		types = ( types || "" ).match( rnothtmlwhite ) || [ "" ];
5020		t = types.length;
5021		while ( t-- ) {
5022			tmp = rtypenamespace.exec( types[ t ] ) || [];
5023			type = origType = tmp[ 1 ];
5024			namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort();
5025
5026			// There *must* be a type, no attaching namespace-only handlers
5027			if ( !type ) {
5028				continue;
5029			}
5030
5031			// If event changes its type, use the special event handlers for the changed type
5032			special = jQuery.event.special[ type ] || {};
5033
5034			// If selector defined, determine special event api type, otherwise given type
5035			type = ( selector ? special.delegateType : special.bindType ) || type;
5036
5037			// Update special based on newly reset type
5038			special = jQuery.event.special[ type ] || {};
5039
5040			// handleObj is passed to all event handlers
5041			handleObj = jQuery.extend( {
5042				type: type,
5043				origType: origType,
5044				data: data,
5045				handler: handler,
5046				guid: handler.guid,
5047				selector: selector,
5048				needsContext: selector && jQuery.expr.match.needsContext.test( selector ),
5049				namespace: namespaces.join( "." )
5050			}, handleObjIn );
5051
5052			// Init the event handler queue if we're the first
5053			if ( !( handlers = events[ type ] ) ) {
5054				handlers = events[ type ] = [];
5055				handlers.delegateCount = 0;
5056
5057				// Only use addEventListener if the special events handler returns false
5058				if ( !special.setup ||
5059					special.setup.call( elem, data, namespaces, eventHandle ) === false ) {
5060
5061					if ( elem.addEventListener ) {
5062						elem.addEventListener( type, eventHandle );
5063					}
5064				}
5065			}
5066
5067			if ( special.add ) {
5068				special.add.call( elem, handleObj );
5069
5070				if ( !handleObj.handler.guid ) {
5071					handleObj.handler.guid = handler.guid;
5072				}
5073			}
5074
5075			// Add to the element's handler list, delegates in front
5076			if ( selector ) {
5077				handlers.splice( handlers.delegateCount++, 0, handleObj );
5078			} else {
5079				handlers.push( handleObj );
5080			}
5081
5082			// Keep track of which events have ever been used, for event optimization
5083			jQuery.event.global[ type ] = true;
5084		}
5085
5086	},
5087
5088	// Detach an event or set of events from an element
5089	remove: function( elem, types, handler, selector, mappedTypes ) {
5090
5091		var j, origCount, tmp,
5092			events, t, handleObj,
5093			special, handlers, type, namespaces, origType,
5094			elemData = dataPriv.hasData( elem ) && dataPriv.get( elem );
5095
5096		if ( !elemData || !( events = elemData.events ) ) {
5097			return;
5098		}
5099
5100		// Once for each type.namespace in types; type may be omitted
5101		types = ( types || "" ).match( rnothtmlwhite ) || [ "" ];
5102		t = types.length;
5103		while ( t-- ) {
5104			tmp = rtypenamespace.exec( types[ t ] ) || [];
5105			type = origType = tmp[ 1 ];
5106			namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort();
5107
5108			// Unbind all events (on this namespace, if provided) for the element
5109			if ( !type ) {
5110				for ( type in events ) {
5111					jQuery.event.remove( elem, type + types[ t ], handler, selector, true );
5112				}
5113				continue;
5114			}
5115
5116			special = jQuery.event.special[ type ] || {};
5117			type = ( selector ? special.delegateType : special.bindType ) || type;
5118			handlers = events[ type ] || [];
5119			tmp = tmp[ 2 ] &&
5120				new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" );
5121
5122			// Remove matching events
5123			origCount = j = handlers.length;
5124			while ( j-- ) {
5125				handleObj = handlers[ j ];
5126
5127				if ( ( mappedTypes || origType === handleObj.origType ) &&
5128					( !handler || handler.guid === handleObj.guid ) &&
5129					( !tmp || tmp.test( handleObj.namespace ) ) &&
5130					( !selector || selector === handleObj.selector ||
5131						selector === "**" && handleObj.selector ) ) {
5132					handlers.splice( j, 1 );
5133
5134					if ( handleObj.selector ) {
5135						handlers.delegateCount--;
5136					}
5137					if ( special.remove ) {
5138						special.remove.call( elem, handleObj );
5139					}
5140				}
5141			}
5142
5143			// Remove generic event handler if we removed something and no more handlers exist
5144			// (avoids potential for endless recursion during removal of special event handlers)
5145			if ( origCount && !handlers.length ) {
5146				if ( !special.teardown ||
5147					special.teardown.call( elem, namespaces, elemData.handle ) === false ) {
5148
5149					jQuery.removeEvent( elem, type, elemData.handle );
5150				}
5151
5152				delete events[ type ];
5153			}
5154		}
5155
5156		// Remove data and the expando if it's no longer used
5157		if ( jQuery.isEmptyObject( events ) ) {
5158			dataPriv.remove( elem, "handle events" );
5159		}
5160	},
5161
5162	dispatch: function( nativeEvent ) {
5163
5164		// Make a writable jQuery.Event from the native event object
5165		var event = jQuery.event.fix( nativeEvent );
5166
5167		var i, j, ret, matched, handleObj, handlerQueue,
5168			args = new Array( arguments.length ),
5169			handlers = ( dataPriv.get( this, "events" ) || {} )[ event.type ] || [],
5170			special = jQuery.event.special[ event.type ] || {};
5171
5172		// Use the fix-ed jQuery.Event rather than the (read-only) native event
5173		args[ 0 ] = event;
5174
5175		for ( i = 1; i < arguments.length; i++ ) {
5176			args[ i ] = arguments[ i ];
5177		}
5178
5179		event.delegateTarget = this;
5180
5181		// Call the preDispatch hook for the mapped type, and let it bail if desired
5182		if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) {
5183			return;
5184		}
5185
5186		// Determine handlers
5187		handlerQueue = jQuery.event.handlers.call( this, event, handlers );
5188
5189		// Run delegates first; they may want to stop propagation beneath us
5190		i = 0;
5191		while ( ( matched = handlerQueue[ i++ ] ) && !event.isPropagationStopped() ) {
5192			event.currentTarget = matched.elem;
5193
5194			j = 0;
5195			while ( ( handleObj = matched.handlers[ j++ ] ) &&
5196				!event.isImmediatePropagationStopped() ) {
5197
5198				// Triggered event must either 1) have no namespace, or 2) have namespace(s)
5199				// a subset or equal to those in the bound event (both can have no namespace).
5200				if ( !event.rnamespace || event.rnamespace.test( handleObj.namespace ) ) {
5201
5202					event.handleObj = handleObj;
5203					event.data = handleObj.data;
5204
5205					ret = ( ( jQuery.event.special[ handleObj.origType ] || {} ).handle ||
5206						handleObj.handler ).apply( matched.elem, args );
5207
5208					if ( ret !== undefined ) {
5209						if ( ( event.result = ret ) === false ) {
5210							event.preventDefault();
5211							event.stopPropagation();
5212						}
5213					}
5214				}
5215			}
5216		}
5217
5218		// Call the postDispatch hook for the mapped type
5219		if ( special.postDispatch ) {
5220			special.postDispatch.call( this, event );
5221		}
5222
5223		return event.result;
5224	},
5225
5226	handlers: function( event, handlers ) {
5227		var i, handleObj, sel, matchedHandlers, matchedSelectors,
5228			handlerQueue = [],
5229			delegateCount = handlers.delegateCount,
5230			cur = event.target;
5231
5232		// Find delegate handlers
5233		if ( delegateCount &&
5234
5235			// Support: IE <=9
5236			// Black-hole SVG <use> instance trees (trac-13180)
5237			cur.nodeType &&
5238
5239			// Support: Firefox <=42
5240			// Suppress spec-violating clicks indicating a non-primary pointer button (trac-3861)
5241			// https://www.w3.org/TR/DOM-Level-3-Events/#event-type-click
5242			// Support: IE 11 only
5243			// ...but not arrow key "clicks" of radio inputs, which can have `button` -1 (gh-2343)
5244			!( event.type === "click" && event.button >= 1 ) ) {
5245
5246			for ( ; cur !== this; cur = cur.parentNode || this ) {
5247
5248				// Don't check non-elements (#13208)
5249				// Don't process clicks on disabled elements (#6911, #8165, #11382, #11764)
5250				if ( cur.nodeType === 1 && !( event.type === "click" && cur.disabled === true ) ) {
5251					matchedHandlers = [];
5252					matchedSelectors = {};
5253					for ( i = 0; i < delegateCount; i++ ) {
5254						handleObj = handlers[ i ];
5255
5256						// Don't conflict with Object.prototype properties (#13203)
5257						sel = handleObj.selector + " ";
5258
5259						if ( matchedSelectors[ sel ] === undefined ) {
5260							matchedSelectors[ sel ] = handleObj.needsContext ?
5261								jQuery( sel, this ).index( cur ) > -1 :
5262								jQuery.find( sel, this, null, [ cur ] ).length;
5263						}
5264						if ( matchedSelectors[ sel ] ) {
5265							matchedHandlers.push( handleObj );
5266						}
5267					}
5268					if ( matchedHandlers.length ) {
5269						handlerQueue.push( { elem: cur, handlers: matchedHandlers } );
5270					}
5271				}
5272			}
5273		}
5274
5275		// Add the remaining (directly-bound) handlers
5276		cur = this;
5277		if ( delegateCount < handlers.length ) {
5278			handlerQueue.push( { elem: cur, handlers: handlers.slice( delegateCount ) } );
5279		}
5280
5281		return handlerQueue;
5282	},
5283
5284	addProp: function( name, hook ) {
5285		Object.defineProperty( jQuery.Event.prototype, name, {
5286			enumerable: true,
5287			configurable: true,
5288
5289			get: 
vendor: 8,400 bytes, lines 5289-5638
5289jQuery.isFunction( hook ) ?
5290				function() {
5291					if ( this.originalEvent ) {
5292							return hook( this.originalEvent );
5293					}
5294				} :
5295				function() {
5296					if ( this.originalEvent ) {
5297							return this.originalEvent[ name ];
5298					}
5299				},
5300
5301			set: function( value ) {
5302				Object.defineProperty( this, name, {
5303					enumerable: true,
5304					configurable: true,
5305					writable: true,
5306					value: value
5307				} );
5308			}
5309		} );
5310	},
5311
5312	fix: function( originalEvent ) {
5313		return originalEvent[ jQuery.expando ] ?
5314			originalEvent :
5315			new jQuery.Event( originalEvent );
5316	},
5317
5318	special: {
5319		load: {
5320
5321			// Prevent triggered image.load events from bubbling to window.load
5322			noBubble: true
5323		},
5324		focus: {
5325
5326			// Fire native event if possible so blur/focus sequence is correct
5327			trigger: function() {
5328				if ( this !== safeActiveElement() && this.focus ) {
5329					this.focus();
5330					return false;
5331				}
5332			},
5333			delegateType: "focusin"
5334		},
5335		blur: {
5336			trigger: function() {
5337				if ( this === safeActiveElement() && this.blur ) {
5338					this.blur();
5339					return false;
5340				}
5341			},
5342			delegateType: "focusout"
5343		},
5344		click: {
5345
5346			// For checkbox, fire native event so checked state will be right
5347			trigger: function() {
5348				if ( this.type === "checkbox" && this.click && nodeName( this, "input" ) ) {
5349					this.click();
5350					return false;
5351				}
5352			},
5353
5354			// For cross-browser consistency, don't fire native .click() on links
5355			_default: function( event ) {
5356				return nodeName( event.target, "a" );
5357			}
5358		},
5359
5360		beforeunload: {
5361			postDispatch: function( event ) {
5362
5363				// Support: Firefox 20+
5364				// Firefox doesn't alert if the returnValue field is not set.
5365				if ( event.result !== undefined && event.originalEvent ) {
5366					event.originalEvent.returnValue = event.result;
5367				}
5368			}
5369		}
5370	}
5371};
5372
5373jQuery.removeEvent = function( elem, type, handle ) {
5374
5375	// This "if" is needed for plain objects
5376	if ( elem.removeEventListener ) {
5377		elem.removeEventListener( type, handle );
5378	}
5379};
5380
5381jQuery.Event = function( src, props ) {
5382
5383	// Allow instantiation without the 'new' keyword
5384	if ( !( this instanceof jQuery.Event ) ) {
5385		return new jQuery.Event( src, props );
5386	}
5387
5388	// Event object
5389	if ( src && src.type ) {
5390		this.originalEvent = src;
5391		this.type = src.type;
5392
5393		// Events bubbling up the document may have been marked as prevented
5394		// by a handler lower down the tree; reflect the correct value.
5395		this.isDefaultPrevented = src.defaultPrevented ||
5396				src.defaultPrevented === undefined &&
5397
5398				// Support: Android <=2.3 only
5399				src.returnValue === false ?
5400			returnTrue :
5401			returnFalse;
5402
5403		// Create target properties
5404		// Support: Safari <=6 - 7 only
5405		// Target should not be a text node (#504, #13143)
5406		this.target = ( src.target && src.target.nodeType === 3 ) ?
5407			src.target.parentNode :
5408			src.target;
5409
5410		this.currentTarget = src.currentTarget;
5411		this.relatedTarget = src.relatedTarget;
5412
5413	// Event type
5414	} else {
5415		this.type = src;
5416	}
5417
5418	// Put explicitly provided properties onto the event object
5419	if ( props ) {
5420		jQuery.extend( this, props );
5421	}
5422
5423	// Create a timestamp if incoming event doesn't have one
5424	this.timeStamp = src && src.timeStamp || jQuery.now();
5425
5426	// Mark it as fixed
5427	this[ jQuery.expando ] = true;
5428};
5429
5430// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding
5431// https://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html
5432jQuery.Event.prototype = {
5433	constructor: jQuery.Event,
5434	isDefaultPrevented: returnFalse,
5435	isPropagationStopped: returnFalse,
5436	isImmediatePropagationStopped: returnFalse,
5437	isSimulated: false,
5438
5439	preventDefault: function() {
5440		var e = this.originalEvent;
5441
5442		this.isDefaultPrevented = returnTrue;
5443
5444		if ( e && !this.isSimulated ) {
5445			e.preventDefault();
5446		}
5447	},
5448	stopPropagation: function() {
5449		var e = this.originalEvent;
5450
5451		this.isPropagationStopped = returnTrue;
5452
5453		if ( e && !this.isSimulated ) {
5454			e.stopPropagation();
5455		}
5456	},
5457	stopImmediatePropagation: function() {
5458		var e = this.originalEvent;
5459
5460		this.isImmediatePropagationStopped = returnTrue;
5461
5462		if ( e && !this.isSimulated ) {
5463			e.stopImmediatePropagation();
5464		}
5465
5466		this.stopPropagation();
5467	}
5468};
5469
5470// Includes all common event props including KeyEvent and MouseEvent specific props
5471jQuery.each( {
5472	altKey: true,
5473	bubbles: true,
5474	cancelable: true,
5475	changedTouches: true,
5476	ctrlKey: true,
5477	detail: true,
5478	eventPhase: true,
5479	metaKey: true,
5480	pageX: true,
5481	pageY: true,
5482	shiftKey: true,
5483	view: true,
5484	"char": true,
5485	charCode: true,
5486	key: true,
5487	keyCode: true,
5488	button: true,
5489	buttons: true,
5490	clientX: true,
5491	clientY: true,
5492	offsetX: true,
5493	offsetY: true,
5494	pointerId: true,
5495	pointerType: true,
5496	screenX: true,
5497	screenY: true,
5498	targetTouches: true,
5499	toElement: true,
5500	touches: true,
5501
5502	which: function( event ) {
5503		var button = event.button;
5504
5505		// Add which for key events
5506		if ( event.which == null && rkeyEvent.test( event.type ) ) {
5507			return event.charCode != null ? event.charCode : event.keyCode;
5508		}
5509
5510		// Add which for click: 1 === left; 2 === middle; 3 === right
5511		if ( !event.which && button !== undefined && rmouseEvent.test( event.type ) ) {
5512			if ( button & 1 ) {
5513				return 1;
5514			}
5515
5516			if ( button & 2 ) {
5517				return 3;
5518			}
5519
5520			if ( button & 4 ) {
5521				return 2;
5522			}
5523
5524			return 0;
5525		}
5526
5527		return event.which;
5528	}
5529}, jQuery.event.addProp );
5530
5531// Create mouseenter/leave events using mouseover/out and event-time checks
5532// so that event delegation works in jQuery.
5533// Do the same for pointerenter/pointerleave and pointerover/pointerout
5534//
5535// Support: Safari 7 only
5536// Safari sends mouseenter too often; see:
5537// https://bugs.chromium.org/p/chromium/issues/detail?id=470258
5538// for the description of the bug (it existed in older Chrome versions as well).
5539jQuery.each( {
5540	mouseenter: "mouseover",
5541	mouseleave: "mouseout",
5542	pointerenter: "pointerover",
5543	pointerleave: "pointerout"
5544}, function( orig, fix ) {
5545	jQuery.event.special[ orig ] = {
5546		delegateType: fix,
5547		bindType: fix,
5548
5549		handle: function( event ) {
5550			var ret,
5551				target = this,
5552				related = event.relatedTarget,
5553				handleObj = event.handleObj;
5554
5555			// For mouseenter/leave call the handler if related is outside the target.
5556			// NB: No relatedTarget if the mouse left/entered the browser window
5557			if ( !related || ( related !== target && !jQuery.contains( target, related ) ) ) {
5558				event.type = handleObj.origType;
5559				ret = handleObj.handler.apply( this, arguments );
5560				event.type = fix;
5561			}
5562			return ret;
5563		}
5564	};
5565} );
5566
5567jQuery.fn.extend( {
5568
5569	on: function( types, selector, data, fn ) {
5570		return on( this, types, selector, data, fn );
5571	},
5572	one: function( types, selector, data, fn ) {
5573		return on( this, types, selector, data, fn, 1 );
5574	},
5575	off: function( types, selector, fn ) {
5576		var handleObj, type;
5577		if ( types && types.preventDefault && types.handleObj ) {
5578
5579			// ( event )  dispatched jQuery.Event
5580			handleObj = types.handleObj;
5581			jQuery( types.delegateTarget ).off(
5582				handleObj.namespace ?
5583					handleObj.origType + "." + handleObj.namespace :
5584					handleObj.origType,
5585				handleObj.selector,
5586				handleObj.handler
5587			);
5588			return this;
5589		}
5590		if ( typeof types === "object" ) {
5591
5592			// ( types-object [, selector] )
5593			for ( type in types ) {
5594				this.off( type, selector, types[ type ] );
5595			}
5596			return this;
5597		}
5598		if ( selector === false || typeof selector === "function" ) {
5599
5600			// ( types [, fn] )
5601			fn = selector;
5602			selector = undefined;
5603		}
5604		if ( fn === false ) {
5605			fn = returnFalse;
5606		}
5607		return this.each( function() {
5608			jQuery.event.remove( this, types, fn, selector );
5609		} );
5610	}
5611} );
5612
5613
5614var
5615
5616	/* eslint-disable max-len */
5617
5618	// See https://github.com/eslint/eslint/issues/3229
5619	rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([a-z][^\/\0>\x20\t\r\n\f]*)[^>]*)\/>/gi,
5620
5621	/* eslint-enable */
5622
5623	// Support: IE <=10 - 11, Edge 12 - 13
5624	// In IE/Edge using regex groups here causes severe slowdowns.
5625	// See https://connect.microsoft.com/IE/feedback/details/1736512/
5626	rnoInnerhtml = /<script|<style|<link/i,
5627
5628	// checked="checked" or checked
5629	rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i,
5630	rscriptTypeMasked = /^true\/(.*)/,
5631	rcleanScript = /^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g;
5632
5633// Prefer a tbody over its parent table for containing new rows
5634function manipulationTarget( elem, content ) {
5635	if ( nodeName( elem, "table" ) &&
5636		nodeName( content.nodeType !== 11 ? content : content.firstChild, "tr" ) ) {
5637
5638		return jQuery( ">tbody", elem
vendor: 6,531 bytes, lines 5638-5886
5638 )[ 0 ] || elem;
5639	}
5640
5641	return elem;
5642}
5643
5644// Replace/restore the type attribute of script elements for safe DOM manipulation
5645function disableScript( elem ) {
5646	elem.type = ( elem.getAttribute( "type" ) !== null ) + "/" + elem.type;
5647	return elem;
5648}
5649function restoreScript( elem ) {
5650	var match = rscriptTypeMasked.exec( elem.type );
5651
5652	if ( match ) {
5653		elem.type = match[ 1 ];
5654	} else {
5655		elem.removeAttribute( "type" );
5656	}
5657
5658	return elem;
5659}
5660
5661function cloneCopyEvent( src, dest ) {
5662	var i, l, type, pdataOld, pdataCur, udataOld, udataCur, events;
5663
5664	if ( dest.nodeType !== 1 ) {
5665		return;
5666	}
5667
5668	// 1. Copy private data: events, handlers, etc.
5669	if ( dataPriv.hasData( src ) ) {
5670		pdataOld = dataPriv.access( src );
5671		pdataCur = dataPriv.set( dest, pdataOld );
5672		events = pdataOld.events;
5673
5674		if ( events ) {
5675			delete pdataCur.handle;
5676			pdataCur.events = {};
5677
5678			for ( type in events ) {
5679				for ( i = 0, l = events[ type ].length; i < l; i++ ) {
5680					jQuery.event.add( dest, type, events[ type ][ i ] );
5681				}
5682			}
5683		}
5684	}
5685
5686	// 2. Copy user data
5687	if ( dataUser.hasData( src ) ) {
5688		udataOld = dataUser.access( src );
5689		udataCur = jQuery.extend( {}, udataOld );
5690
5691		dataUser.set( dest, udataCur );
5692	}
5693}
5694
5695// Fix IE bugs, see support tests
5696function fixInput( src, dest ) {
5697	var nodeName = dest.nodeName.toLowerCase();
5698
5699	// Fails to persist the checked state of a cloned checkbox or radio button.
5700	if ( nodeName === "input" && rcheckableType.test( src.type ) ) {
5701		dest.checked = src.checked;
5702
5703	// Fails to return the selected option to the default selected state when cloning options
5704	} else if ( nodeName === "input" || nodeName === "textarea" ) {
5705		dest.defaultValue = src.defaultValue;
5706	}
5707}
5708
5709function domManip( collection, args, callback, ignored ) {
5710
5711	// Flatten any nested arrays
5712	args = concat.apply( [], args );
5713
5714	var fragment, first, scripts, hasScripts, node, doc,
5715		i = 0,
5716		l = collection.length,
5717		iNoClone = l - 1,
5718		value = args[ 0 ],
5719		isFunction = jQuery.isFunction( value );
5720
5721	// We can't cloneNode fragments that contain checked, in WebKit
5722	if ( isFunction ||
5723			( l > 1 && typeof value === "string" &&
5724				!support.checkClone && rchecked.test( value ) ) ) {
5725		return collection.each( function( index ) {
5726			var self = collection.eq( index );
5727			if ( isFunction ) {
5728				args[ 0 ] = value.call( this, index, self.html() );
5729			}
5730			domManip( self, args, callback, ignored );
5731		} );
5732	}
5733
5734	if ( l ) {
5735		fragment = buildFragment( args, collection[ 0 ].ownerDocument, false, collection, ignored );
5736		first = fragment.firstChild;
5737
5738		if ( fragment.childNodes.length === 1 ) {
5739			fragment = first;
5740		}
5741
5742		// Require either new content or an interest in ignored elements to invoke the callback
5743		if ( first || ignored ) {
5744			scripts = jQuery.map( getAll( fragment, "script" ), disableScript );
5745			hasScripts = scripts.length;
5746
5747			// Use the original fragment for the last item
5748			// instead of the first because it can end up
5749			// being emptied incorrectly in certain situations (#8070).
5750			for ( ; i < l; i++ ) {
5751				node = fragment;
5752
5753				if ( i !== iNoClone ) {
5754					node = jQuery.clone( node, true, true );
5755
5756					// Keep references to cloned scripts for later restoration
5757					if ( hasScripts ) {
5758
5759						// Support: Android <=4.0 only, PhantomJS 1 only
5760						// push.apply(_, arraylike) throws on ancient WebKit
5761						jQuery.merge( scripts, getAll( node, "script" ) );
5762					}
5763				}
5764
5765				callback.call( collection[ i ], node, i );
5766			}
5767
5768			if ( hasScripts ) {
5769				doc = scripts[ scripts.length - 1 ].ownerDocument;
5770
5771				// Reenable scripts
5772				jQuery.map( scripts, restoreScript );
5773
5774				// Evaluate executable scripts on first document insertion
5775				for ( i = 0; i < hasScripts; i++ ) {
5776					node = scripts[ i ];
5777					if ( rscriptType.test( node.type || "" ) &&
5778						!dataPriv.access( node, "globalEval" ) &&
5779						jQuery.contains( doc, node ) ) {
5780
5781						if ( node.src ) {
5782
5783							// Optional AJAX dependency, but won't run scripts if not present
5784							if ( jQuery._evalUrl ) {
5785								jQuery._evalUrl( node.src );
5786							}
5787						} else {
5788							DOMEval( node.textContent.replace( rcleanScript, "" ), doc );
5789						}
5790					}
5791				}
5792			}
5793		}
5794	}
5795
5796	return collection;
5797}
5798
5799function remove( elem, selector, keepData ) {
5800	var node,
5801		nodes = selector ? jQuery.filter( selector, elem ) : elem,
5802		i = 0;
5803
5804	for ( ; ( node = nodes[ i ] ) != null; i++ ) {
5805		if ( !keepData && node.nodeType === 1 ) {
5806			jQuery.cleanData( getAll( node ) );
5807		}
5808
5809		if ( node.parentNode ) {
5810			if ( keepData && jQuery.contains( node.ownerDocument, node ) ) {
5811				setGlobalEval( getAll( node, "script" ) );
5812			}
5813			node.parentNode.removeChild( node );
5814		}
5815	}
5816
5817	return elem;
5818}
5819
5820jQuery.extend( {
5821	htmlPrefilter: function( html ) {
5822		return html.replace( rxhtmlTag, "<$1></$2>" );
5823	},
5824
5825	clone: function( elem, dataAndEvents, deepDataAndEvents ) {
5826		var i, l, srcElements, destElements,
5827			clone = elem.cloneNode( true ),
5828			inPage = jQuery.contains( elem.ownerDocument, elem );
5829
5830		// Fix IE cloning issues
5831		if ( !support.noCloneChecked && ( elem.nodeType === 1 || elem.nodeType === 11 ) &&
5832				!jQuery.isXMLDoc( elem ) ) {
5833
5834			// We eschew Sizzle here for performance reasons: https://jsperf.com/getall-vs-sizzle/2
5835			destElements = getAll( clone );
5836			srcElements = getAll( elem );
5837
5838			for ( i = 0, l = srcElements.length; i < l; i++ ) {
5839				fixInput( srcElements[ i ], destElements[ i ] );
5840			}
5841		}
5842
5843		// Copy the events from the original to the clone
5844		if ( dataAndEvents ) {
5845			if ( deepDataAndEvents ) {
5846				srcElements = srcElements || getAll( elem );
5847				destElements = destElements || getAll( clone );
5848
5849				for ( i = 0, l = srcElements.length; i < l; i++ ) {
5850					cloneCopyEvent( srcElements[ i ], destElements[ i ] );
5851				}
5852			} else {
5853				cloneCopyEvent( elem, clone );
5854			}
5855		}
5856
5857		// Preserve script evaluation history
5858		destElements = getAll( clone, "script" );
5859		if ( destElements.length > 0 ) {
5860			setGlobalEval( destElements, !inPage && getAll( elem, "script" ) );
5861		}
5862
5863		// Return the cloned set
5864		return clone;
5865	},
5866
5867	cleanData: function( elems ) {
5868		var data, elem, type,
5869			special = jQuery.event.special,
5870			i = 0;
5871
5872		for ( ; ( elem = elems[ i ] ) !== undefined; i++ ) {
5873			if ( acceptData( elem ) ) {
5874				if ( ( data = elem[ dataPriv.expando ] ) ) {
5875					if ( data.events ) {
5876						for ( type in data.events ) {
5877							if ( special[ type ] ) {
5878								jQuery.event.remove( elem, type );
5879
5880							// This is a shortcut to avoid jQuery.event.remove's overhead
5881							} else {
5882								jQuery.removeEvent( elem, type, data.handle );
5883							}
5884						}
5885					}
5886
vendor: 1,119 bytes, lines 5887-5931
5887					// Support: Chrome <=35 - 45+
5888					// Assign undefined instead of using delete, see Data#remove
5889					elem[ dataPriv.expando ] = undefined;
5890				}
5891				if ( elem[ dataUser.expando ] ) {
5892
5893					// Support: Chrome <=35 - 45+
5894					// Assign undefined instead of using delete, see Data#remove
5895					elem[ dataUser.expando ] = undefined;
5896				}
5897			}
5898		}
5899	}
5900} );
5901
5902jQuery.fn.extend( {
5903	detach: function( selector ) {
5904		return remove( this, selector, true );
5905	},
5906
5907	remove: function( selector ) {
5908		return remove( this, selector );
5909	},
5910
5911	text: function( value ) {
5912		return access( this, function( value ) {
5913			return value === undefined ?
5914				jQuery.text( this ) :
5915				this.empty().each( function() {
5916					if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
5917						this.textContent = value;
5918					}
5919				} );
5920		}, null, value, arguments.length );
5921	},
5922
5923	append: function() {
5924		return domManip( this, arguments, function( elem ) {
5925			if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
5926				var target = manipulationTarget( this, elem );
5927				target.appendChild( elem );
5928			}
5929		} );
5930	},
5931
vendor: 6,076 bytes, lines 5932-6167
5932	prepend: function() {
5933		return domManip( this, arguments, function( elem ) {
5934			if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
5935				var target = manipulationTarget( this, elem );
5936				target.insertBefore( elem, target.firstChild );
5937			}
5938		} );
5939	},
5940
5941	before: function() {
5942		return domManip( this, arguments, function( elem ) {
5943			if ( this.parentNode ) {
5944				this.parentNode.insertBefore( elem, this );
5945			}
5946		} );
5947	},
5948
5949	after: function() {
5950		return domManip( this, arguments, function( elem ) {
5951			if ( this.parentNode ) {
5952				this.parentNode.insertBefore( elem, this.nextSibling );
5953			}
5954		} );
5955	},
5956
5957	empty: function() {
5958		var elem,
5959			i = 0;
5960
5961		for ( ; ( elem = this[ i ] ) != null; i++ ) {
5962			if ( elem.nodeType === 1 ) {
5963
5964				// Prevent memory leaks
5965				jQuery.cleanData( getAll( elem, false ) );
5966
5967				// Remove any remaining nodes
5968				elem.textContent = "";
5969			}
5970		}
5971
5972		return this;
5973	},
5974
5975	clone: function( dataAndEvents, deepDataAndEvents ) {
5976		dataAndEvents = dataAndEvents == null ? false : dataAndEvents;
5977		deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents;
5978
5979		return this.map( function() {
5980			return jQuery.clone( this, dataAndEvents, deepDataAndEvents );
5981		} );
5982	},
5983
5984	html: function( value ) {
5985		return access( this, function( value ) {
5986			var elem = this[ 0 ] || {},
5987				i = 0,
5988				l = this.length;
5989
5990			if ( value === undefined && elem.nodeType === 1 ) {
5991				return elem.innerHTML;
5992			}
5993
5994			// See if we can take a shortcut and just use innerHTML
5995			if ( typeof value === "string" && !rnoInnerhtml.test( value ) &&
5996				!wrapMap[ ( rtagName.exec( value ) || [ "", "" ] )[ 1 ].toLowerCase() ] ) {
5997
5998				value = jQuery.htmlPrefilter( value );
5999
6000				try {
6001					for ( ; i < l; i++ ) {
6002						elem = this[ i ] || {};
6003
6004						// Remove element nodes and prevent memory leaks
6005						if ( elem.nodeType === 1 ) {
6006							jQuery.cleanData( getAll( elem, false ) );
6007							elem.innerHTML = value;
6008						}
6009					}
6010
6011					elem = 0;
6012
6013				// If using innerHTML throws an exception, use the fallback method
6014				} catch ( e ) {}
6015			}
6016
6017			if ( elem ) {
6018				this.empty().append( value );
6019			}
6020		}, null, value, arguments.length );
6021	},
6022
6023	replaceWith: function() {
6024		var ignored = [];
6025
6026		// Make the changes, replacing each non-ignored context element with the new content
6027		return domManip( this, arguments, function( elem ) {
6028			var parent = this.parentNode;
6029
6030			if ( jQuery.inArray( this, ignored ) < 0 ) {
6031				jQuery.cleanData( getAll( this ) );
6032				if ( parent ) {
6033					parent.replaceChild( elem, this );
6034				}
6035			}
6036
6037		// Force callback invocation
6038		}, ignored );
6039	}
6040} );
6041
6042jQuery.each( {
6043	appendTo: "append",
6044	prependTo: "prepend",
6045	insertBefore: "before",
6046	insertAfter: "after",
6047	replaceAll: "replaceWith"
6048}, function( name, original ) {
6049	jQuery.fn[ name ] = function( selector ) {
6050		var elems,
6051			ret = [],
6052			insert = jQuery( selector ),
6053			last = insert.length - 1,
6054			i = 0;
6055
6056		for ( ; i <= last; i++ ) {
6057			elems = i === last ? this : this.clone( true );
6058			jQuery( insert[ i ] )[ original ]( elems );
6059
6060			// Support: Android <=4.0 only, PhantomJS 1 only
6061			// .get() because push.apply(_, arraylike) throws on ancient WebKit
6062			push.apply( ret, elems.get() );
6063		}
6064
6065		return this.pushStack( ret );
6066	};
6067} );
6068var rmargin = ( /^margin/ );
6069
6070var rnumnonpx = new RegExp( "^(" + pnum + ")(?!px)[a-z%]+$", "i" );
6071
6072var getStyles = function( elem ) {
6073
6074		// Support: IE <=11 only, Firefox <=30 (#15098, #14150)
6075		// IE throws on elements created in popups
6076		// FF meanwhile throws on frame elements through "defaultView.getComputedStyle"
6077		var view = elem.ownerDocument.defaultView;
6078
6079		if ( !view || !view.opener ) {
6080			view = window;
6081		}
6082
6083		return view.getComputedStyle( elem );
6084	};
6085
6086
6087
6088( function() {
6089
6090	// Executing both pixelPosition & boxSizingReliable tests require only one layout
6091	// so they're executed at the same time to save the second computation.
6092	function computeStyleTests() {
6093
6094		// This is a singleton, we need to execute it only once
6095		if ( !div ) {
6096			return;
6097		}
6098
6099		div.style.cssText =
6100			"box-sizing:border-box;" +
6101			"position:relative;display:block;" +
6102			"margin:auto;border:1px;padding:1px;" +
6103			"top:1%;width:50%";
6104		div.innerHTML = "";
6105		documentElement.appendChild( container );
6106
6107		var divStyle = window.getComputedStyle( div );
6108		pixelPositionVal = divStyle.top !== "1%";
6109
6110		// Support: Android 4.0 - 4.3 only, Firefox <=3 - 44
6111		reliableMarginLeftVal = divStyle.marginLeft === "2px";
6112		boxSizingReliableVal = divStyle.width === "4px";
6113
6114		// Support: Android 4.0 - 4.3 only
6115		// Some styles come back with percentage values, even though they shouldn't
6116		div.style.marginRight = "50%";
6117		pixelMarginRightVal = divStyle.marginRight === "4px";
6118
6119		documentElement.removeChild( container );
6120
6121		// Nullify the div so it wouldn't be stored in the memory and
6122		// it will also be a sign that checks already performed
6123		div = null;
6124	}
6125
6126	var pixelPositionVal, boxSizingReliableVal, pixelMarginRightVal, reliableMarginLeftVal,
6127		container = document.createElement( "div" ),
6128		div = document.createElement( "div" );
6129
6130	// Finish early in limited (non-browser) environments
6131	if ( !div.style ) {
6132		return;
6133	}
6134
6135	// Support: IE <=9 - 11 only
6136	// Style of cloned element affects source element cloned (#8908)
6137	div.style.backgroundClip = "content-box";
6138	div.cloneNode( true ).style.backgroundClip = "";
6139	support.clearCloneStyle = div.style.backgroundClip === "content-box";
6140
6141	container.style.cssText = "border:0;width:8px;height:0;top:0;left:-9999px;" +
6142		"padding:0;margin-top:1px;position:absolute";
6143	container.appendChild( div );
6144
6145	jQuery.extend( support, {
6146		pixelPosition: function() {
6147			computeStyleTests();
6148			return pixelPositionVal;
6149		},
6150		boxSizingReliable: function() {
6151			computeStyleTests();
6152			return boxSizingReliableVal;
6153		},
6154		pixelMarginRight: function() {
6155			computeStyleTests();
6156			return pixelMarginRightVal;
6157		},
6158		reliableMarginLeft: function() {
6159			computeStyleTests();
6160			return reliableMarginLeftVal;
6161		}
6162	} );
6163} )();
6164
6165
6166function curCSS( elem, name, computed ) {
6167	var width, minWidth, maxWidth, ret,
vendor: 8,366 bytes, lines 6168-6473
6168
6169		// Support: Firefox 51+
6170		// Retrieving style before computed somehow
6171		// fixes an issue with getting wrong values
6172		// on detached elements
6173		style = elem.style;
6174
6175	computed = computed || getStyles( elem );
6176
6177	// getPropertyValue is needed for:
6178	//   .css('filter') (IE 9 only, #12537)
6179	//   .css('--customProperty) (#3144)
6180	if ( computed ) {
6181		ret = computed.getPropertyValue( name ) || computed[ name ];
6182
6183		if ( ret === "" && !jQuery.contains( elem.ownerDocument, elem ) ) {
6184			ret = jQuery.style( elem, name );
6185		}
6186
6187		// A tribute to the "awesome hack by Dean Edwards"
6188		// Android Browser returns percentage for some values,
6189		// but width seems to be reliably pixels.
6190		// This is against the CSSOM draft spec:
6191		// https://drafts.csswg.org/cssom/#resolved-values
6192		if ( !support.pixelMarginRight() && rnumnonpx.test( ret ) && rmargin.test( name ) ) {
6193
6194			// Remember the original values
6195			width = style.width;
6196			minWidth = style.minWidth;
6197			maxWidth = style.maxWidth;
6198
6199			// Put in the new values to get a computed value out
6200			style.minWidth = style.maxWidth = style.width = ret;
6201			ret = computed.width;
6202
6203			// Revert the changed values
6204			style.width = width;
6205			style.minWidth = minWidth;
6206			style.maxWidth = maxWidth;
6207		}
6208	}
6209
6210	return ret !== undefined ?
6211
6212		// Support: IE <=9 - 11 only
6213		// IE returns zIndex value as an integer.
6214		ret + "" :
6215		ret;
6216}
6217
6218
6219function addGetHookIf( conditionFn, hookFn ) {
6220
6221	// Define the hook, we'll check on the first run if it's really needed.
6222	return {
6223		get: function() {
6224			if ( conditionFn() ) {
6225
6226				// Hook not needed (or it's not possible to use it due
6227				// to missing dependency), remove it.
6228				delete this.get;
6229				return;
6230			}
6231
6232			// Hook needed; redefine it so that the support test is not executed again.
6233			return ( this.get = hookFn ).apply( this, arguments );
6234		}
6235	};
6236}
6237
6238
6239var
6240
6241	// Swappable if display is none or starts with table
6242	// except "table", "table-cell", or "table-caption"
6243	// See here for display values: https://developer.mozilla.org/en-US/docs/CSS/display
6244	rdisplayswap = /^(none|table(?!-c[ea]).+)/,
6245	rcustomProp = /^--/,
6246	cssShow = { position: "absolute", visibility: "hidden", display: "block" },
6247	cssNormalTransform = {
6248		letterSpacing: "0",
6249		fontWeight: "400"
6250	},
6251
6252	cssPrefixes = [ "Webkit", "Moz", "ms" ],
6253	emptyStyle = document.createElement( "div" ).style;
6254
6255// Return a css property mapped to a potentially vendor prefixed property
6256function vendorPropName( name ) {
6257
6258	// Shortcut for names that are not vendor prefixed
6259	if ( name in emptyStyle ) {
6260		return name;
6261	}
6262
6263	// Check for vendor prefixed names
6264	var capName = name[ 0 ].toUpperCase() + name.slice( 1 ),
6265		i = cssPrefixes.length;
6266
6267	while ( i-- ) {
6268		name = cssPrefixes[ i ] + capName;
6269		if ( name in emptyStyle ) {
6270			return name;
6271		}
6272	}
6273}
6274
6275// Return a property mapped along what jQuery.cssProps suggests or to
6276// a vendor prefixed property.
6277function finalPropName( name ) {
6278	var ret = jQuery.cssProps[ name ];
6279	if ( !ret ) {
6280		ret = jQuery.cssProps[ name ] = vendorPropName( name ) || name;
6281	}
6282	return ret;
6283}
6284
6285function setPositiveNumber( elem, value, subtract ) {
6286
6287	// Any relative (+/-) values have already been
6288	// normalized at this point
6289	var matches = rcssNum.exec( value );
6290	return matches ?
6291
6292		// Guard against undefined "subtract", e.g., when used as in cssHooks
6293		Math.max( 0, matches[ 2 ] - ( subtract || 0 ) ) + ( matches[ 3 ] || "px" ) :
6294		value;
6295}
6296
6297function augmentWidthOrHeight( elem, name, extra, isBorderBox, styles ) {
6298	var i,
6299		val = 0;
6300
6301	// If we already have the right measurement, avoid augmentation
6302	if ( extra === ( isBorderBox ? "border" : "content" ) ) {
6303		i = 4;
6304
6305	// Otherwise initialize for horizontal or vertical properties
6306	} else {
6307		i = name === "width" ? 1 : 0;
6308	}
6309
6310	for ( ; i < 4; i += 2 ) {
6311
6312		// Both box models exclude margin, so add it if we want it
6313		if ( extra === "margin" ) {
6314			val += jQuery.css( elem, extra + cssExpand[ i ], true, styles );
6315		}
6316
6317		if ( isBorderBox ) {
6318
6319			// border-box includes padding, so remove it if we want content
6320			if ( extra === "content" ) {
6321				val -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles );
6322			}
6323
6324			// At this point, extra isn't border nor margin, so remove border
6325			if ( extra !== "margin" ) {
6326				val -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles );
6327			}
6328		} else {
6329
6330			// At this point, extra isn't content, so add padding
6331			val += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles );
6332
6333			// At this point, extra isn't content nor padding, so add border
6334			if ( extra !== "padding" ) {
6335				val += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles );
6336			}
6337		}
6338	}
6339
6340	return val;
6341}
6342
6343function getWidthOrHeight( elem, name, extra ) {
6344
6345	// Start with computed style
6346	var valueIsBorderBox,
6347		styles = getStyles( elem ),
6348		val = curCSS( elem, name, styles ),
6349		isBorderBox = jQuery.css( elem, "boxSizing", false, styles ) === "border-box";
6350
6351	// Computed unit is not pixels. Stop here and return.
6352	if ( rnumnonpx.test( val ) ) {
6353		return val;
6354	}
6355
6356	// Check for style in case a browser which returns unreliable values
6357	// for getComputedStyle silently falls back to the reliable elem.style
6358	valueIsBorderBox = isBorderBox &&
6359		( support.boxSizingReliable() || val === elem.style[ name ] );
6360
6361	// Fall back to offsetWidth/Height when value is "auto"
6362	// This happens for inline elements with no explicit setting (gh-3571)
6363	if ( val === "auto" ) {
6364		val = elem[ "offset" + name[ 0 ].toUpperCase() + name.slice( 1 ) ];
6365	}
6366
6367	// Normalize "", auto, and prepare for extra
6368	val = parseFloat( val ) || 0;
6369
6370	// Use the active box-sizing model to add/subtract irrelevant styles
6371	return ( val +
6372		augmentWidthOrHeight(
6373			elem,
6374			name,
6375			extra || ( isBorderBox ? "border" : "content" ),
6376			valueIsBorderBox,
6377			styles
6378		)
6379	) + "px";
6380}
6381
6382jQuery.extend( {
6383
6384	// Add in style property hooks for overriding the default
6385	// behavior of getting and setting a style property
6386	cssHooks: {
6387		opacity: {
6388			get: function( elem, computed ) {
6389				if ( computed ) {
6390
6391					// We should always get a number back from opacity
6392					var ret = curCSS( elem, "opacity" );
6393					return ret === "" ? "1" : ret;
6394				}
6395			}
6396		}
6397	},
6398
6399	// Don't automatically add "px" to these possibly-unitless properties
6400	cssNumber: {
6401		"animationIterationCount": true,
6402		"columnCount": true,
6403		"fillOpacity": true,
6404		"flexGrow": true,
6405		"flexShrink": true,
6406		"fontWeight": true,
6407		"lineHeight": true,
6408		"opacity": true,
6409		"order": true,
6410		"orphans": true,
6411		"widows": true,
6412		"zIndex": true,
6413		"zoom": true
6414	},
6415
6416	// Add in properties whose names you wish to fix before
6417	// setting or getting the value
6418	cssProps: {
6419		"float": "cssFloat"
6420	},
6421
6422	// Get and set the style property on a DOM Node
6423	style: function( elem, name, value, extra ) {
6424
6425		// Don't set styles on text and comment nodes
6426		if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) {
6427			return;
6428		}
6429
6430		// Make sure that we're working with the right name
6431		var ret, type, hooks,
6432			origName = jQuery.camelCase( name ),
6433			isCustomProp = rcustomProp.test( name ),
6434			style = elem.style;
6435
6436		// Make sure that we're working with the right name. We don't
6437		// want to query the value if it is a CSS custom property
6438		// since they are user-defined.
6439		if ( !isCustomProp ) {
6440			name = finalPropName( origName );
6441		}
6442
6443		// Gets hook for the prefixed version, then unprefixed version
6444		hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];
6445
6446		// Check if we're setting a value
6447		if ( value !== undefined ) {
6448			type = typeof value;
6449
6450			// Convert "+=" or "-=" to relative numbers (#7345)
6451			if ( type === "string" && ( ret = rcssNum.exec( value ) ) && ret[ 1 ] ) {
6452				value = adjustCSS( elem, name, ret );
6453
6454				// Fixes bug #9237
6455				type = "number";
6456			}
6457
6458			// Make sure that null and NaN values aren't set (#7116)
6459			if ( value == null || value !== value ) {
6460				return;
6461			}
6462
6463			// If a number was passed in, add the unit (except for certain CSS properties)
6464			if ( type === "number" ) {
6465				value += ret && ret[ 3 ] || ( jQuery.cssNumber[ origName ] ? "" : "px" );
6466			}
6467
6468			// background-* props affect original clone's values
6469			if ( !support.clearCloneStyle && value === "" && name.indexOf( "background" ) === 0 ) {
6470				style[ name ] = "inherit";
6471			}
6472
6473			// If a hook was provided, use that value, otherwise just set the specified value
vendor: 4,779 bytes, lines 6474-6656
6474			if ( !hooks || !( "set" in hooks ) ||
6475				( value = hooks.set( elem, value, extra ) ) !== undefined ) {
6476
6477				if ( isCustomProp ) {
6478					style.setProperty( name, value );
6479				} else {
6480					style[ name ] = value;
6481				}
6482			}
6483
6484		} else {
6485
6486			// If a hook was provided get the non-computed value from there
6487			if ( hooks && "get" in hooks &&
6488				( ret = hooks.get( elem, false, extra ) ) !== undefined ) {
6489
6490				return ret;
6491			}
6492
6493			// Otherwise just get the value from the style object
6494			return style[ name ];
6495		}
6496	},
6497
6498	css: function( elem, name, extra, styles ) {
6499		var val, num, hooks,
6500			origName = jQuery.camelCase( name ),
6501			isCustomProp = rcustomProp.test( name );
6502
6503		// Make sure that we're working with the right name. We don't
6504		// want to modify the value if it is a CSS custom property
6505		// since they are user-defined.
6506		if ( !isCustomProp ) {
6507			name = finalPropName( origName );
6508		}
6509
6510		// Try prefixed name followed by the unprefixed name
6511		hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];
6512
6513		// If a hook was provided get the computed value from there
6514		if ( hooks && "get" in hooks ) {
6515			val = hooks.get( elem, true, extra );
6516		}
6517
6518		// Otherwise, if a way to get the computed value exists, use that
6519		if ( val === undefined ) {
6520			val = curCSS( elem, name, styles );
6521		}
6522
6523		// Convert "normal" to computed value
6524		if ( val === "normal" && name in cssNormalTransform ) {
6525			val = cssNormalTransform[ name ];
6526		}
6527
6528		// Make numeric if forced or a qualifier was provided and val looks numeric
6529		if ( extra === "" || extra ) {
6530			num = parseFloat( val );
6531			return extra === true || isFinite( num ) ? num || 0 : val;
6532		}
6533
6534		return val;
6535	}
6536} );
6537
6538jQuery.each( [ "height", "width" ], function( i, name ) {
6539	jQuery.cssHooks[ name ] = {
6540		get: function( elem, computed, extra ) {
6541			if ( computed ) {
6542
6543				// Certain elements can have dimension info if we invisibly show them
6544				// but it must have a current display style that would benefit
6545				return rdisplayswap.test( jQuery.css( elem, "display" ) ) &&
6546
6547					// Support: Safari 8+
6548					// Table columns in Safari have non-zero offsetWidth & zero
6549					// getBoundingClientRect().width unless display is changed.
6550					// Support: IE <=11 only
6551					// Running getBoundingClientRect on a disconnected node
6552					// in IE throws an error.
6553					( !elem.getClientRects().length || !elem.getBoundingClientRect().width ) ?
6554						swap( elem, cssShow, function() {
6555							return getWidthOrHeight( elem, name, extra );
6556						} ) :
6557						getWidthOrHeight( elem, name, extra );
6558			}
6559		},
6560
6561		set: function( elem, value, extra ) {
6562			var matches,
6563				styles = extra && getStyles( elem ),
6564				subtract = extra && augmentWidthOrHeight(
6565					elem,
6566					name,
6567					extra,
6568					jQuery.css( elem, "boxSizing", false, styles ) === "border-box",
6569					styles
6570				);
6571
6572			// Convert to pixels if value adjustment is needed
6573			if ( subtract && ( matches = rcssNum.exec( value ) ) &&
6574				( matches[ 3 ] || "px" ) !== "px" ) {
6575
6576				elem.style[ name ] = value;
6577				value = jQuery.css( elem, name );
6578			}
6579
6580			return setPositiveNumber( elem, value, subtract );
6581		}
6582	};
6583} );
6584
6585jQuery.cssHooks.marginLeft = addGetHookIf( support.reliableMarginLeft,
6586	function( elem, computed ) {
6587		if ( computed ) {
6588			return ( parseFloat( curCSS( elem, "marginLeft" ) ) ||
6589				elem.getBoundingClientRect().left -
6590					swap( elem, { marginLeft: 0 }, function() {
6591						return elem.getBoundingClientRect().left;
6592					} )
6593				) + "px";
6594		}
6595	}
6596);
6597
6598// These hooks are used by animate to expand properties
6599jQuery.each( {
6600	margin: "",
6601	padding: "",
6602	border: "Width"
6603}, function( prefix, suffix ) {
6604	jQuery.cssHooks[ prefix + suffix ] = {
6605		expand: function( value ) {
6606			var i = 0,
6607				expanded = {},
6608
6609				// Assumes a single number if not a string
6610				parts = typeof value === "string" ? value.split( " " ) : [ value ];
6611
6612			for ( ; i < 4; i++ ) {
6613				expanded[ prefix + cssExpand[ i ] + suffix ] =
6614					parts[ i ] || parts[ i - 2 ] || parts[ 0 ];
6615			}
6616
6617			return expanded;
6618		}
6619	};
6620
6621	if ( !rmargin.test( prefix ) ) {
6622		jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber;
6623	}
6624} );
6625
6626jQuery.fn.extend( {
6627	css: function( name, value ) {
6628		return access( this, function( elem, name, value ) {
6629			var styles, len,
6630				map = {},
6631				i = 0;
6632
6633			if ( Array.isArray( name ) ) {
6634				styles = getStyles( elem );
6635				len = name.length;
6636
6637				for ( ; i < len; i++ ) {
6638					map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles );
6639				}
6640
6641				return map;
6642			}
6643
6644			return value !== undefined ?
6645				jQuery.style( elem, name, value ) :
6646				jQuery.css( elem, name );
6647		}, name, value, arguments.length > 1 );
6648	}
6649} );
6650
6651
6652function Tween( elem, options, prop, end, easing ) {
6653	return new Tween.prototype.init( elem, options, prop, end, easing );
6654}
6655jQuery.Tween = Tween;
6656
vendor: 6,216 bytes, lines 6657-6895
6657Tween.prototype = {
6658	constructor: Tween,
6659	init: function( elem, options, prop, end, easing, unit ) {
6660		this.elem = elem;
6661		this.prop = prop;
6662		this.easing = easing || jQuery.easing._default;
6663		this.options = options;
6664		this.start = this.now = this.cur();
6665		this.end = end;
6666		this.unit = unit || ( jQuery.cssNumber[ prop ] ? "" : "px" );
6667	},
6668	cur: function() {
6669		var hooks = Tween.propHooks[ this.prop ];
6670
6671		return hooks && hooks.get ?
6672			hooks.get( this ) :
6673			Tween.propHooks._default.get( this );
6674	},
6675	run: function( percent ) {
6676		var eased,
6677			hooks = Tween.propHooks[ this.prop ];
6678
6679		if ( this.options.duration ) {
6680			this.pos = eased = jQuery.easing[ this.easing ](
6681				percent, this.options.duration * percent, 0, 1, this.options.duration
6682			);
6683		} else {
6684			this.pos = eased = percent;
6685		}
6686		this.now = ( this.end - this.start ) * eased + this.start;
6687
6688		if ( this.options.step ) {
6689			this.options.step.call( this.elem, this.now, this );
6690		}
6691
6692		if ( hooks && hooks.set ) {
6693			hooks.set( this );
6694		} else {
6695			Tween.propHooks._default.set( this );
6696		}
6697		return this;
6698	}
6699};
6700
6701Tween.prototype.init.prototype = Tween.prototype;
6702
6703Tween.propHooks = {
6704	_default: {
6705		get: function( tween ) {
6706			var result;
6707
6708			// Use a property on the element directly when it is not a DOM element,
6709			// or when there is no matching style property that exists.
6710			if ( tween.elem.nodeType !== 1 ||
6711				tween.elem[ tween.prop ] != null && tween.elem.style[ tween.prop ] == null ) {
6712				return tween.elem[ tween.prop ];
6713			}
6714
6715			// Passing an empty string as a 3rd parameter to .css will automatically
6716			// attempt a parseFloat and fallback to a string if the parse fails.
6717			// Simple values such as "10px" are parsed to Float;
6718			// complex values such as "rotate(1rad)" are returned as-is.
6719			result = jQuery.css( tween.elem, tween.prop, "" );
6720
6721			// Empty strings, null, undefined and "auto" are converted to 0.
6722			return !result || result === "auto" ? 0 : result;
6723		},
6724		set: function( tween ) {
6725
6726			// Use step hook for back compat.
6727			// Use cssHook if its there.
6728			// Use .style if available and use plain properties where available.
6729			if ( jQuery.fx.step[ tween.prop ] ) {
6730				jQuery.fx.step[ tween.prop ]( tween );
6731			} else if ( tween.elem.nodeType === 1 &&
6732				( tween.elem.style[ jQuery.cssProps[ tween.prop ] ] != null ||
6733					jQuery.cssHooks[ tween.prop ] ) ) {
6734				jQuery.style( tween.elem, tween.prop, tween.now + tween.unit );
6735			} else {
6736				tween.elem[ tween.prop ] = tween.now;
6737			}
6738		}
6739	}
6740};
6741
6742// Support: IE <=9 only
6743// Panic based approach to setting things on disconnected nodes
6744Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = {
6745	set: function( tween ) {
6746		if ( tween.elem.nodeType && tween.elem.parentNode ) {
6747			tween.elem[ tween.prop ] = tween.now;
6748		}
6749	}
6750};
6751
6752jQuery.easing = {
6753	linear: function( p ) {
6754		return p;
6755	},
6756	swing: function( p ) {
6757		return 0.5 - Math.cos( p * Math.PI ) / 2;
6758	},
6759	_default: "swing"
6760};
6761
6762jQuery.fx = Tween.prototype.init;
6763
6764// Back compat <1.8 extension point
6765jQuery.fx.step = {};
6766
6767
6768
6769
6770var
6771	fxNow, inProgress,
6772	rfxtypes = /^(?:toggle|show|hide)$/,
6773	rrun = /queueHooks$/;
6774
6775function schedule() {
6776	if ( inProgress ) {
6777		if ( document.hidden === false && window.requestAnimationFrame ) {
6778			window.requestAnimationFrame( schedule );
6779		} else {
6780			window.setTimeout( schedule, jQuery.fx.interval );
6781		}
6782
6783		jQuery.fx.tick();
6784	}
6785}
6786
6787// Animations created synchronously will run synchronously
6788function createFxNow() {
6789	window.setTimeout( function() {
6790		fxNow = undefined;
6791	} );
6792	return ( fxNow = jQuery.now() );
6793}
6794
6795// Generate parameters to create a standard animation
6796function genFx( type, includeWidth ) {
6797	var which,
6798		i = 0,
6799		attrs = { height: type };
6800
6801	// If we include width, step value is 1 to do all cssExpand values,
6802	// otherwise step value is 2 to skip over Left and Right
6803	includeWidth = includeWidth ? 1 : 0;
6804	for ( ; i < 4; i += 2 - includeWidth ) {
6805		which = cssExpand[ i ];
6806		attrs[ "margin" + which ] = attrs[ "padding" + which ] = type;
6807	}
6808
6809	if ( includeWidth ) {
6810		attrs.opacity = attrs.width = type;
6811	}
6812
6813	return attrs;
6814}
6815
6816function createTween( value, prop, animation ) {
6817	var tween,
6818		collection = ( Animation.tweeners[ prop ] || [] ).concat( Animation.tweeners[ "*" ] ),
6819		index = 0,
6820		length = collection.length;
6821	for ( ; index < length; index++ ) {
6822		if ( ( tween = collection[ index ].call( animation, prop, value ) ) ) {
6823
6824			// We're done with this property
6825			return tween;
6826		}
6827	}
6828}
6829
6830function defaultPrefilter( elem, props, opts ) {
6831	var prop, value, toggle, hooks, oldfire, propTween, restoreDisplay, display,
6832		isBox = "width" in props || "height" in props,
6833		anim = this,
6834		orig = {},
6835		style = elem.style,
6836		hidden = elem.nodeType && isHiddenWithinTree( elem ),
6837		dataShow = dataPriv.get( elem, "fxshow" );
6838
6839	// Queue-skipping animations hijack the fx hooks
6840	if ( !opts.queue ) {
6841		hooks = jQuery._queueHooks( elem, "fx" );
6842		if ( hooks.unqueued == null ) {
6843			hooks.unqueued = 0;
6844			oldfire = hooks.empty.fire;
6845			hooks.empty.fire = function() {
6846				if ( !hooks.unqueued ) {
6847					oldfire();
6848				}
6849			};
6850		}
6851		hooks.unqueued++;
6852
6853		anim.always( function() {
6854
6855			// Ensure the complete handler is called before this completes
6856			anim.always( function() {
6857				hooks.unqueued--;
6858				if ( !jQuery.queue( elem, "fx" ).length ) {
6859					hooks.empty.fire();
6860				}
6861			} );
6862		} );
6863	}
6864
6865	// Detect show/hide animations
6866	for ( prop in props ) {
6867		value = props[ prop ];
6868		if ( rfxtypes.test( value ) ) {
6869			delete props[ prop ];
6870			toggle = toggle || value === "toggle";
6871			if ( value === ( hidden ? "hide" : "show" ) ) {
6872
6873				// Pretend to be hidden if this is a "show" and
6874				// there is still data from a stopped show/hide
6875				if ( value === "show" && dataShow && dataShow[ prop ] !== undefined ) {
6876					hidden = true;
6877
6878				// Ignore all other no-op show/hide data
6879				} else {
6880					continue;
6881				}
6882			}
6883			orig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop );
6884		}
6885	}
6886
6887	// Bail out if this is a no-op like .hide().hide()
6888	propTween = !jQuery.isEmptyObject( props );
6889	if ( !propTween && jQuery.isEmptyObject( orig ) ) {
6890		return;
6891	}
6892
6893	// Restrict "overflow" and "display" styles during box animations
6894	if ( isBox && elem.nodeType === 1 ) {
6895
vendor: 4,173 bytes, lines 6896-7054
6896		// Support: IE <=9 - 11, Edge 12 - 13
6897		// Record all 3 overflow attributes because IE does not infer the shorthand
6898		// from identically-valued overflowX and overflowY
6899		opts.overflow = [ style.overflow, style.overflowX, style.overflowY ];
6900
6901		// Identify a display type, preferring old show/hide data over the CSS cascade
6902		restoreDisplay = dataShow && dataShow.display;
6903		if ( restoreDisplay == null ) {
6904			restoreDisplay = dataPriv.get( elem, "display" );
6905		}
6906		display = jQuery.css( elem, "display" );
6907		if ( display === "none" ) {
6908			if ( restoreDisplay ) {
6909				display = restoreDisplay;
6910			} else {
6911
6912				// Get nonempty value(s) by temporarily forcing visibility
6913				showHide( [ elem ], true );
6914				restoreDisplay = elem.style.display || restoreDisplay;
6915				display = jQuery.css( elem, "display" );
6916				showHide( [ elem ] );
6917			}
6918		}
6919
6920		// Animate inline elements as inline-block
6921		if ( display === "inline" || display === "inline-block" && restoreDisplay != null ) {
6922			if ( jQuery.css( elem, "float" ) === "none" ) {
6923
6924				// Restore the original display value at the end of pure show/hide animations
6925				if ( !propTween ) {
6926					anim.done( function() {
6927						style.display = restoreDisplay;
6928					} );
6929					if ( restoreDisplay == null ) {
6930						display = style.display;
6931						restoreDisplay = display === "none" ? "" : display;
6932					}
6933				}
6934				style.display = "inline-block";
6935			}
6936		}
6937	}
6938
6939	if ( opts.overflow ) {
6940		style.overflow = "hidden";
6941		anim.always( function() {
6942			style.overflow = opts.overflow[ 0 ];
6943			style.overflowX = opts.overflow[ 1 ];
6944			style.overflowY = opts.overflow[ 2 ];
6945		} );
6946	}
6947
6948	// Implement show/hide animations
6949	propTween = false;
6950	for ( prop in orig ) {
6951
6952		// General show/hide setup for this element animation
6953		if ( !propTween ) {
6954			if ( dataShow ) {
6955				if ( "hidden" in dataShow ) {
6956					hidden = dataShow.hidden;
6957				}
6958			} else {
6959				dataShow = dataPriv.access( elem, "fxshow", { display: restoreDisplay } );
6960			}
6961
6962			// Store hidden/visible for toggle so `.stop().toggle()` "reverses"
6963			if ( toggle ) {
6964				dataShow.hidden = !hidden;
6965			}
6966
6967			// Show elements before animating them
6968			if ( hidden ) {
6969				showHide( [ elem ], true );
6970			}
6971
6972			/* eslint-disable no-loop-func */
6973
6974			anim.done( function() {
6975
6976			/* eslint-enable no-loop-func */
6977
6978				// The final step of a "hide" animation is actually hiding the element
6979				if ( !hidden ) {
6980					showHide( [ elem ] );
6981				}
6982				dataPriv.remove( elem, "fxshow" );
6983				for ( prop in orig ) {
6984					jQuery.style( elem, prop, orig[ prop ] );
6985				}
6986			} );
6987		}
6988
6989		// Per-property setup
6990		propTween = createTween( hidden ? dataShow[ prop ] : 0, prop, anim );
6991		if ( !( prop in dataShow ) ) {
6992			dataShow[ prop ] = propTween.start;
6993			if ( hidden ) {
6994				propTween.end = propTween.start;
6995				propTween.start = 0;
6996			}
6997		}
6998	}
6999}
7000
7001function propFilter( props, specialEasing ) {
7002	var index, name, easing, value, hooks;
7003
7004	// camelCase, specialEasing and expand cssHook pass
7005	for ( index in props ) {
7006		name = jQuery.camelCase( index );
7007		easing = specialEasing[ name ];
7008		value = props[ index ];
7009		if ( Array.isArray( value ) ) {
7010			easing = value[ 1 ];
7011			value = props[ index ] = value[ 0 ];
7012		}
7013
7014		if ( index !== name ) {
7015			props[ name ] = value;
7016			delete props[ index ];
7017		}
7018
7019		hooks = jQuery.cssHooks[ name ];
7020		if ( hooks && "expand" in hooks ) {
7021			value = hooks.expand( value );
7022			delete props[ name ];
7023
7024			// Not quite $.extend, this won't overwrite existing keys.
7025			// Reusing 'index' because we have the correct "name"
7026			for ( index in value ) {
7027				if ( !( index in props ) ) {
7028					props[ index ] = value[ index ];
7029					specialEasing[ index ] = easing;
7030				}
7031			}
7032		} else {
7033			specialEasing[ name ] = easing;
7034		}
7035	}
7036}
7037
7038function Animation( elem, properties, options ) {
7039	var result,
7040		stopped,
7041		index = 0,
7042		length = Animation.prefilters.length,
7043		deferred = jQuery.Deferred().always( function() {
7044
7045			// Don't match elem in the :animated selector
7046			delete tick.elem;
7047		} ),
7048		tick = function() {
7049			if ( stopped ) {
7050				return false;
7051			}
7052			var currentTime = fxNow || createFxNow(),
7053				remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ),
7054
vendor: 6,686 bytes, lines 7055-7314
7055				// Support: Android 2.3 only
7056				// Archaic crash bug won't allow us to use `1 - ( 0.5 || 0 )` (#12497)
7057				temp = remaining / animation.duration || 0,
7058				percent = 1 - temp,
7059				index = 0,
7060				length = animation.tweens.length;
7061
7062			for ( ; index < length; index++ ) {
7063				animation.tweens[ index ].run( percent );
7064			}
7065
7066			deferred.notifyWith( elem, [ animation, percent, remaining ] );
7067
7068			// If there's more to do, yield
7069			if ( percent < 1 && length ) {
7070				return remaining;
7071			}
7072
7073			// If this was an empty animation, synthesize a final progress notification
7074			if ( !length ) {
7075				deferred.notifyWith( elem, [ animation, 1, 0 ] );
7076			}
7077
7078			// Resolve the animation and report its conclusion
7079			deferred.resolveWith( elem, [ animation ] );
7080			return false;
7081		},
7082		animation = deferred.promise( {
7083			elem: elem,
7084			props: jQuery.extend( {}, properties ),
7085			opts: jQuery.extend( true, {
7086				specialEasing: {},
7087				easing: jQuery.easing._default
7088			}, options ),
7089			originalProperties: properties,
7090			originalOptions: options,
7091			startTime: fxNow || createFxNow(),
7092			duration: options.duration,
7093			tweens: [],
7094			createTween: function( prop, end ) {
7095				var tween = jQuery.Tween( elem, animation.opts, prop, end,
7096						animation.opts.specialEasing[ prop ] || animation.opts.easing );
7097				animation.tweens.push( tween );
7098				return tween;
7099			},
7100			stop: function( gotoEnd ) {
7101				var index = 0,
7102
7103					// If we are going to the end, we want to run all the tweens
7104					// otherwise we skip this part
7105					length = gotoEnd ? animation.tweens.length : 0;
7106				if ( stopped ) {
7107					return this;
7108				}
7109				stopped = true;
7110				for ( ; index < length; index++ ) {
7111					animation.tweens[ index ].run( 1 );
7112				}
7113
7114				// Resolve when we played the last frame; otherwise, reject
7115				if ( gotoEnd ) {
7116					deferred.notifyWith( elem, [ animation, 1, 0 ] );
7117					deferred.resolveWith( elem, [ animation, gotoEnd ] );
7118				} else {
7119					deferred.rejectWith( elem, [ animation, gotoEnd ] );
7120				}
7121				return this;
7122			}
7123		} ),
7124		props = animation.props;
7125
7126	propFilter( props, animation.opts.specialEasing );
7127
7128	for ( ; index < length; index++ ) {
7129		result = Animation.prefilters[ index ].call( animation, elem, props, animation.opts );
7130		if ( result ) {
7131			if ( jQuery.isFunction( result.stop ) ) {
7132				jQuery._queueHooks( animation.elem, animation.opts.queue ).stop =
7133					jQuery.proxy( result.stop, result );
7134			}
7135			return result;
7136		}
7137	}
7138
7139	jQuery.map( props, createTween, animation );
7140
7141	if ( jQuery.isFunction( animation.opts.start ) ) {
7142		animation.opts.start.call( elem, animation );
7143	}
7144
7145	// Attach callbacks from options
7146	animation
7147		.progress( animation.opts.progress )
7148		.done( animation.opts.done, animation.opts.complete )
7149		.fail( animation.opts.fail )
7150		.always( animation.opts.always );
7151
7152	jQuery.fx.timer(
7153		jQuery.extend( tick, {
7154			elem: elem,
7155			anim: animation,
7156			queue: animation.opts.queue
7157		} )
7158	);
7159
7160	return animation;
7161}
7162
7163jQuery.Animation = jQuery.extend( Animation, {
7164
7165	tweeners: {
7166		"*": [ function( prop, value ) {
7167			var tween = this.createTween( prop, value );
7168			adjustCSS( tween.elem, prop, rcssNum.exec( value ), tween );
7169			return tween;
7170		} ]
7171	},
7172
7173	tweener: function( props, callback ) {
7174		if ( jQuery.isFunction( props ) ) {
7175			callback = props;
7176			props = [ "*" ];
7177		} else {
7178			props = props.match( rnothtmlwhite );
7179		}
7180
7181		var prop,
7182			index = 0,
7183			length = props.length;
7184
7185		for ( ; index < length; index++ ) {
7186			prop = props[ index ];
7187			Animation.tweeners[ prop ] = Animation.tweeners[ prop ] || [];
7188			Animation.tweeners[ prop ].unshift( callback );
7189		}
7190	},
7191
7192	prefilters: [ defaultPrefilter ],
7193
7194	prefilter: function( callback, prepend ) {
7195		if ( prepend ) {
7196			Animation.prefilters.unshift( callback );
7197		} else {
7198			Animation.prefilters.push( callback );
7199		}
7200	}
7201} );
7202
7203jQuery.speed = function( speed, easing, fn ) {
7204	var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : {
7205		complete: fn || !fn && easing ||
7206			jQuery.isFunction( speed ) && speed,
7207		duration: speed,
7208		easing: fn && easing || easing && !jQuery.isFunction( easing ) && easing
7209	};
7210
7211	// Go to the end state if fx are off
7212	if ( jQuery.fx.off ) {
7213		opt.duration = 0;
7214
7215	} else {
7216		if ( typeof opt.duration !== "number" ) {
7217			if ( opt.duration in jQuery.fx.speeds ) {
7218				opt.duration = jQuery.fx.speeds[ opt.duration ];
7219
7220			} else {
7221				opt.duration = jQuery.fx.speeds._default;
7222			}
7223		}
7224	}
7225
7226	// Normalize opt.queue - true/undefined/null -> "fx"
7227	if ( opt.queue == null || opt.queue === true ) {
7228		opt.queue = "fx";
7229	}
7230
7231	// Queueing
7232	opt.old = opt.complete;
7233
7234	opt.complete = function() {
7235		if ( jQuery.isFunction( opt.old ) ) {
7236			opt.old.call( this );
7237		}
7238
7239		if ( opt.queue ) {
7240			jQuery.dequeue( this, opt.queue );
7241		}
7242	};
7243
7244	return opt;
7245};
7246
7247jQuery.fn.extend( {
7248	fadeTo: function( speed, to, easing, callback ) {
7249
7250		// Show any hidden elements after setting opacity to 0
7251		return this.filter( isHiddenWithinTree ).css( "opacity", 0 ).show()
7252
7253			// Animate to the value specified
7254			.end().animate( { opacity: to }, speed, easing, callback );
7255	},
7256	animate: function( prop, speed, easing, callback ) {
7257		var empty = jQuery.isEmptyObject( prop ),
7258			optall = jQuery.speed( speed, easing, callback ),
7259			doAnimation = function() {
7260
7261				// Operate on a copy of prop so per-property easing won't be lost
7262				var anim = Animation( this, jQuery.extend( {}, prop ), optall );
7263
7264				// Empty animations, or finishing resolves immediately
7265				if ( empty || dataPriv.get( this, "finish" ) ) {
7266					anim.stop( true );
7267				}
7268			};
7269			doAnimation.finish = doAnimation;
7270
7271		return empty || optall.queue === false ?
7272			this.each( doAnimation ) :
7273			this.queue( optall.queue, doAnimation );
7274	},
7275	stop: function( type, clearQueue, gotoEnd ) {
7276		var stopQueue = function( hooks ) {
7277			var stop = hooks.stop;
7278			delete hooks.stop;
7279			stop( gotoEnd );
7280		};
7281
7282		if ( typeof type !== "string" ) {
7283			gotoEnd = clearQueue;
7284			clearQueue = type;
7285			type = undefined;
7286		}
7287		if ( clearQueue && type !== false ) {
7288			this.queue( type || "fx", [] );
7289		}
7290
7291		return this.each( function() {
7292			var dequeue = true,
7293				index = type != null && type + "queueHooks",
7294				timers = jQuery.timers,
7295				data = dataPriv.get( this );
7296
7297			if ( index ) {
7298				if ( data[ index ] && data[ index ].stop ) {
7299					stopQueue( data[ index ] );
7300				}
7301			} else {
7302				for ( index in data ) {
7303					if ( data[ index ] && data[ index ].stop && rrun.test( index ) ) {
7304						stopQueue( data[ index ] );
7305					}
7306				}
7307			}
7308
7309			for ( index = timers.length; index--; ) {
7310				if ( timers[ index ].elem === this &&
7311					( type == null || timers[ index ].queue === type ) ) {
7312
7313					timers[ index ].anim.stop( gotoEnd );
7314					dequeue = false;
vendor: 2,199 bytes, lines 7315-7399
7315					timers.splice( index, 1 );
7316				}
7317			}
7318
7319			// Start the next in the queue if the last step wasn't forced.
7320			// Timers currently will call their complete callbacks, which
7321			// will dequeue but only if they were gotoEnd.
7322			if ( dequeue || !gotoEnd ) {
7323				jQuery.dequeue( this, type );
7324			}
7325		} );
7326	},
7327	finish: function( type ) {
7328		if ( type !== false ) {
7329			type = type || "fx";
7330		}
7331		return this.each( function() {
7332			var index,
7333				data = dataPriv.get( this ),
7334				queue = data[ type + "queue" ],
7335				hooks = data[ type + "queueHooks" ],
7336				timers = jQuery.timers,
7337				length = queue ? queue.length : 0;
7338
7339			// Enable finishing flag on private data
7340			data.finish = true;
7341
7342			// Empty the queue first
7343			jQuery.queue( this, type, [] );
7344
7345			if ( hooks && hooks.stop ) {
7346				hooks.stop.call( this, true );
7347			}
7348
7349			// Look for any active animations, and finish them
7350			for ( index = timers.length; index--; ) {
7351				if ( timers[ index ].elem === this && timers[ index ].queue === type ) {
7352					timers[ index ].anim.stop( true );
7353					timers.splice( index, 1 );
7354				}
7355			}
7356
7357			// Look for any animations in the old queue and finish them
7358			for ( index = 0; index < length; index++ ) {
7359				if ( queue[ index ] && queue[ index ].finish ) {
7360					queue[ index ].finish.call( this );
7361				}
7362			}
7363
7364			// Turn off finishing flag
7365			delete data.finish;
7366		} );
7367	}
7368} );
7369
7370jQuery.each( [ "toggle", "show", "hide" ], function( i, name ) {
7371	var cssFn = jQuery.fn[ name ];
7372	jQuery.fn[ name ] = function( speed, easing, callback ) {
7373		return speed == null || typeof speed === "boolean" ?
7374			cssFn.apply( this, arguments ) :
7375			this.animate( genFx( name, true ), speed, easing, callback );
7376	};
7377} );
7378
7379// Generate shortcuts for custom animations
7380jQuery.each( {
7381	slideDown: genFx( "show" ),
7382	slideUp: genFx( "hide" ),
7383	slideToggle: genFx( "toggle" ),
7384	fadeIn: { opacity: "show" },
7385	fadeOut: { opacity: "hide" },
7386	fadeToggle: { opacity: "toggle" }
7387}, function( name, props ) {
7388	jQuery.fn[ name ] = function( speed, easing, callback ) {
7389		return this.animate( props, speed, easing, callback );
7390	};
7391} );
7392
7393jQuery.timers = [];
7394jQuery.fx.tick = function() {
7395	var timer,
7396		i = 0,
7397		timers = jQuery.timers;
7398
7399	fxNow = jQuery
vendor: 7,814 bytes, lines 7399-7752
7399.now();
7400
7401	for ( ; i < timers.length; i++ ) {
7402		timer = timers[ i ];
7403
7404		// Run the timer and safely remove it when done (allowing for external removal)
7405		if ( !timer() && timers[ i ] === timer ) {
7406			timers.splice( i--, 1 );
7407		}
7408	}
7409
7410	if ( !timers.length ) {
7411		jQuery.fx.stop();
7412	}
7413	fxNow = undefined;
7414};
7415
7416jQuery.fx.timer = function( timer ) {
7417	jQuery.timers.push( timer );
7418	jQuery.fx.start();
7419};
7420
7421jQuery.fx.interval = 13;
7422jQuery.fx.start = function() {
7423	if ( inProgress ) {
7424		return;
7425	}
7426
7427	inProgress = true;
7428	schedule();
7429};
7430
7431jQuery.fx.stop = function() {
7432	inProgress = null;
7433};
7434
7435jQuery.fx.speeds = {
7436	slow: 600,
7437	fast: 200,
7438
7439	// Default speed
7440	_default: 400
7441};
7442
7443
7444// Based off of the plugin by Clint Helfers, with permission.
7445// https://web.archive.org/web/20100324014747/http://blindsignals.com/index.php/2009/07/jquery-delay/
7446jQuery.fn.delay = function( time, type ) {
7447	time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time;
7448	type = type || "fx";
7449
7450	return this.queue( type, function( next, hooks ) {
7451		var timeout = window.setTimeout( next, time );
7452		hooks.stop = function() {
7453			window.clearTimeout( timeout );
7454		};
7455	} );
7456};
7457
7458
7459( function() {
7460	var input = document.createElement( "input" ),
7461		select = document.createElement( "select" ),
7462		opt = select.appendChild( document.createElement( "option" ) );
7463
7464	input.type = "checkbox";
7465
7466	// Support: Android <=4.3 only
7467	// Default value for a checkbox should be "on"
7468	support.checkOn = input.value !== "";
7469
7470	// Support: IE <=11 only
7471	// Must access selectedIndex to make default options select
7472	support.optSelected = opt.selected;
7473
7474	// Support: IE <=11 only
7475	// An input loses its value after becoming a radio
7476	input = document.createElement( "input" );
7477	input.value = "t";
7478	input.type = "radio";
7479	support.radioValue = input.value === "t";
7480} )();
7481
7482
7483var boolHook,
7484	attrHandle = jQuery.expr.attrHandle;
7485
7486jQuery.fn.extend( {
7487	attr: function( name, value ) {
7488		return access( this, jQuery.attr, name, value, arguments.length > 1 );
7489	},
7490
7491	removeAttr: function( name ) {
7492		return this.each( function() {
7493			jQuery.removeAttr( this, name );
7494		} );
7495	}
7496} );
7497
7498jQuery.extend( {
7499	attr: function( elem, name, value ) {
7500		var ret, hooks,
7501			nType = elem.nodeType;
7502
7503		// Don't get/set attributes on text, comment and attribute nodes
7504		if ( nType === 3 || nType === 8 || nType === 2 ) {
7505			return;
7506		}
7507
7508		// Fallback to prop when attributes are not supported
7509		if ( typeof elem.getAttribute === "undefined" ) {
7510			return jQuery.prop( elem, name, value );
7511		}
7512
7513		// Attribute hooks are determined by the lowercase version
7514		// Grab necessary hook if one is defined
7515		if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) {
7516			hooks = jQuery.attrHooks[ name.toLowerCase() ] ||
7517				( jQuery.expr.match.bool.test( name ) ? boolHook : undefined );
7518		}
7519
7520		if ( value !== undefined ) {
7521			if ( value === null ) {
7522				jQuery.removeAttr( elem, name );
7523				return;
7524			}
7525
7526			if ( hooks && "set" in hooks &&
7527				( ret = hooks.set( elem, value, name ) ) !== undefined ) {
7528				return ret;
7529			}
7530
7531			elem.setAttribute( name, value + "" );
7532			return value;
7533		}
7534
7535		if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) {
7536			return ret;
7537		}
7538
7539		ret = jQuery.find.attr( elem, name );
7540
7541		// Non-existent attributes return null, we normalize to undefined
7542		return ret == null ? undefined : ret;
7543	},
7544
7545	attrHooks: {
7546		type: {
7547			set: function( elem, value ) {
7548				if ( !support.radioValue && value === "radio" &&
7549					nodeName( elem, "input" ) ) {
7550					var val = elem.value;
7551					elem.setAttribute( "type", value );
7552					if ( val ) {
7553						elem.value = val;
7554					}
7555					return value;
7556				}
7557			}
7558		}
7559	},
7560
7561	removeAttr: function( elem, value ) {
7562		var name,
7563			i = 0,
7564
7565			// Attribute names can contain non-HTML whitespace characters
7566			// https://html.spec.whatwg.org/multipage/syntax.html#attributes-2
7567			attrNames = value && value.match( rnothtmlwhite );
7568
7569		if ( attrNames && elem.nodeType === 1 ) {
7570			while ( ( name = attrNames[ i++ ] ) ) {
7571				elem.removeAttribute( name );
7572			}
7573		}
7574	}
7575} );
7576
7577// Hooks for boolean attributes
7578boolHook = {
7579	set: function( elem, value, name ) {
7580		if ( value === false ) {
7581
7582			// Remove boolean attributes when set to false
7583			jQuery.removeAttr( elem, name );
7584		} else {
7585			elem.setAttribute( name, name );
7586		}
7587		return name;
7588	}
7589};
7590
7591jQuery.each( jQuery.expr.match.bool.source.match( /\w+/g ), function( i, name ) {
7592	var getter = attrHandle[ name ] || jQuery.find.attr;
7593
7594	attrHandle[ name ] = function( elem, name, isXML ) {
7595		var ret, handle,
7596			lowercaseName = name.toLowerCase();
7597
7598		if ( !isXML ) {
7599
7600			// Avoid an infinite loop by temporarily removing this function from the getter
7601			handle = attrHandle[ lowercaseName ];
7602			attrHandle[ lowercaseName ] = ret;
7603			ret = getter( elem, name, isXML ) != null ?
7604				lowercaseName :
7605				null;
7606			attrHandle[ lowercaseName ] = handle;
7607		}
7608		return ret;
7609	};
7610} );
7611
7612
7613
7614
7615var rfocusable = /^(?:input|select|textarea|button)$/i,
7616	rclickable = /^(?:a|area)$/i;
7617
7618jQuery.fn.extend( {
7619	prop: function( name, value ) {
7620		return access( this, jQuery.prop, name, value, arguments.length > 1 );
7621	},
7622
7623	removeProp: function( name ) {
7624		return this.each( function() {
7625			delete this[ jQuery.propFix[ name ] || name ];
7626		} );
7627	}
7628} );
7629
7630jQuery.extend( {
7631	prop: function( elem, name, value ) {
7632		var ret, hooks,
7633			nType = elem.nodeType;
7634
7635		// Don't get/set properties on text, comment and attribute nodes
7636		if ( nType === 3 || nType === 8 || nType === 2 ) {
7637			return;
7638		}
7639
7640		if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) {
7641
7642			// Fix name and attach hooks
7643			name = jQuery.propFix[ name ] || name;
7644			hooks = jQuery.propHooks[ name ];
7645		}
7646
7647		if ( value !== undefined ) {
7648			if ( hooks && "set" in hooks &&
7649				( ret = hooks.set( elem, value, name ) ) !== undefined ) {
7650				return ret;
7651			}
7652
7653			return ( elem[ name ] = value );
7654		}
7655
7656		if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) {
7657			return ret;
7658		}
7659
7660		return elem[ name ];
7661	},
7662
7663	propHooks: {
7664		tabIndex: {
7665			get: function( elem ) {
7666
7667				// Support: IE <=9 - 11 only
7668				// elem.tabIndex doesn't always return the
7669				// correct value when it hasn't been explicitly set
7670				// https://web.archive.org/web/20141116233347/http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/
7671				// Use proper attribute retrieval(#12072)
7672				var tabindex = jQuery.find.attr( elem, "tabindex" );
7673
7674				if ( tabindex ) {
7675					return parseInt( tabindex, 10 );
7676				}
7677
7678				if (
7679					rfocusable.test( elem.nodeName ) ||
7680					rclickable.test( elem.nodeName ) &&
7681					elem.href
7682				) {
7683					return 0;
7684				}
7685
7686				return -1;
7687			}
7688		}
7689	},
7690
7691	propFix: {
7692		"for": "htmlFor",
7693		"class": "className"
7694	}
7695} );
7696
7697// Support: IE <=11 only
7698// Accessing the selectedIndex property
7699// forces the browser to respect setting selected
7700// on the option
7701// The getter ensures a default option is selected
7702// when in an optgroup
7703// eslint rule "no-unused-expressions" is disabled for this code
7704// since it considers such accessions noop
7705if ( !support.optSelected ) {
7706	jQuery.propHooks.selected = {
7707		get: function( elem ) {
7708
7709			/* eslint no-unused-expressions: "off" */
7710
7711			var parent = elem.parentNode;
7712			if ( parent && parent.parentNode ) {
7713				parent.parentNode.selectedIndex;
7714			}
7715			return null;
7716		},
7717		set: function( elem ) {
7718
7719			/* eslint no-unused-expressions: "off" */
7720
7721			var parent = elem.parentNode;
7722			if ( parent ) {
7723				parent.selectedIndex;
7724
7725				if ( parent.parentNode ) {
7726					parent.parentNode.selectedIndex;
7727				}
7728			}
7729		}
7730	};
7731}
7732
7733jQuery.each( [
7734	"tabIndex",
7735	"readOnly",
7736	"maxLength",
7737	"cellSpacing",
7738	"cellPadding",
7739	"rowSpan",
7740	"colSpan",
7741	"useMap",
7742	"frameBorder",
7743	"contentEditable"
7744], function() {
7745	jQuery.propFix[ this.toLowerCase() ] = this;
7746} );
7747
7748
7749
7750
7751	// Strip and collapse whitespace according to HTML spec
7752	// https://
vendor: 4,260 bytes, lines 7752-7918
7752html.spec.whatwg.org/multipage/infrastructure.html#strip-and-collapse-whitespace
7753	function stripAndCollapse( value ) {
7754		var tokens = value.match( rnothtmlwhite ) || [];
7755		return tokens.join( " " );
7756	}
7757
7758
7759function getClass( elem ) {
7760	return elem.getAttribute && elem.getAttribute( "class" ) || "";
7761}
7762
7763jQuery.fn.extend( {
7764	addClass: function( value ) {
7765		var classes, elem, cur, curValue, clazz, j, finalValue,
7766			i = 0;
7767
7768		if ( jQuery.isFunction( value ) ) {
7769			return this.each( function( j ) {
7770				jQuery( this ).addClass( value.call( this, j, getClass( this ) ) );
7771			} );
7772		}
7773
7774		if ( typeof value === "string" && value ) {
7775			classes = value.match( rnothtmlwhite ) || [];
7776
7777			while ( ( elem = this[ i++ ] ) ) {
7778				curValue = getClass( elem );
7779				cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " );
7780
7781				if ( cur ) {
7782					j = 0;
7783					while ( ( clazz = classes[ j++ ] ) ) {
7784						if ( cur.indexOf( " " + clazz + " " ) < 0 ) {
7785							cur += clazz + " ";
7786						}
7787					}
7788
7789					// Only assign if different to avoid unneeded rendering.
7790					finalValue = stripAndCollapse( cur );
7791					if ( curValue !== finalValue ) {
7792						elem.setAttribute( "class", finalValue );
7793					}
7794				}
7795			}
7796		}
7797
7798		return this;
7799	},
7800
7801	removeClass: function( value ) {
7802		var classes, elem, cur, curValue, clazz, j, finalValue,
7803			i = 0;
7804
7805		if ( jQuery.isFunction( value ) ) {
7806			return this.each( function( j ) {
7807				jQuery( this ).removeClass( value.call( this, j, getClass( this ) ) );
7808			} );
7809		}
7810
7811		if ( !arguments.length ) {
7812			return this.attr( "class", "" );
7813		}
7814
7815		if ( typeof value === "string" && value ) {
7816			classes = value.match( rnothtmlwhite ) || [];
7817
7818			while ( ( elem = this[ i++ ] ) ) {
7819				curValue = getClass( elem );
7820
7821				// This expression is here for better compressibility (see addClass)
7822				cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " );
7823
7824				if ( cur ) {
7825					j = 0;
7826					while ( ( clazz = classes[ j++ ] ) ) {
7827
7828						// Remove *all* instances
7829						while ( cur.indexOf( " " + clazz + " " ) > -1 ) {
7830							cur = cur.replace( " " + clazz + " ", " " );
7831						}
7832					}
7833
7834					// Only assign if different to avoid unneeded rendering.
7835					finalValue = stripAndCollapse( cur );
7836					if ( curValue !== finalValue ) {
7837						elem.setAttribute( "class", finalValue );
7838					}
7839				}
7840			}
7841		}
7842
7843		return this;
7844	},
7845
7846	toggleClass: function( value, stateVal ) {
7847		var type = typeof value;
7848
7849		if ( typeof stateVal === "boolean" && type === "string" ) {
7850			return stateVal ? this.addClass( value ) : this.removeClass( value );
7851		}
7852
7853		if ( jQuery.isFunction( value ) ) {
7854			return this.each( function( i ) {
7855				jQuery( this ).toggleClass(
7856					value.call( this, i, getClass( this ), stateVal ),
7857					stateVal
7858				);
7859			} );
7860		}
7861
7862		return this.each( function() {
7863			var className, i, self, classNames;
7864
7865			if ( type === "string" ) {
7866
7867				// Toggle individual class names
7868				i = 0;
7869				self = jQuery( this );
7870				classNames = value.match( rnothtmlwhite ) || [];
7871
7872				while ( ( className = classNames[ i++ ] ) ) {
7873
7874					// Check each className given, space separated list
7875					if ( self.hasClass( className ) ) {
7876						self.removeClass( className );
7877					} else {
7878						self.addClass( className );
7879					}
7880				}
7881
7882			// Toggle whole class name
7883			} else if ( value === undefined || type === "boolean" ) {
7884				className = getClass( this );
7885				if ( className ) {
7886
7887					// Store className if set
7888					dataPriv.set( this, "__className__", className );
7889				}
7890
7891				// If the element has a class name or if we're passed `false`,
7892				// then remove the whole classname (if there was one, the above saved it).
7893				// Otherwise bring back whatever was previously saved (if anything),
7894				// falling back to the empty string if nothing was stored.
7895				if ( this.setAttribute ) {
7896					this.setAttribute( "class",
7897						className || value === false ?
7898						"" :
7899						dataPriv.get( this, "__className__" ) || ""
7900					);
7901				}
7902			}
7903		} );
7904	},
7905
7906	hasClass: function( selector ) {
7907		var className, elem,
7908			i = 0;
7909
7910		className = " " + selector + " ";
7911		while ( ( elem = this[ i++ ] ) ) {
7912			if ( elem.nodeType === 1 &&
7913				( " " + stripAndCollapse( getClass( elem ) ) + " " ).indexOf( className ) > -1 ) {
7914					return true;
7915			}
7916		}
7917
7918		return false;
vendor: 1,377 bytes, lines 7919-7988
7919	}
7920} );
7921
7922
7923
7924
7925var rreturn = /\r/g;
7926
7927jQuery.fn.extend( {
7928	val: function( value ) {
7929		var hooks, ret, isFunction,
7930			elem = this[ 0 ];
7931
7932		if ( !arguments.length ) {
7933			if ( elem ) {
7934				hooks = jQuery.valHooks[ elem.type ] ||
7935					jQuery.valHooks[ elem.nodeName.toLowerCase() ];
7936
7937				if ( hooks &&
7938					"get" in hooks &&
7939					( ret = hooks.get( elem, "value" ) ) !== undefined
7940				) {
7941					return ret;
7942				}
7943
7944				ret = elem.value;
7945
7946				// Handle most common string cases
7947				if ( typeof ret === "string" ) {
7948					return ret.replace( rreturn, "" );
7949				}
7950
7951				// Handle cases where value is null/undef or number
7952				return ret == null ? "" : ret;
7953			}
7954
7955			return;
7956		}
7957
7958		isFunction = jQuery.isFunction( value );
7959
7960		return this.each( function( i ) {
7961			var val;
7962
7963			if ( this.nodeType !== 1 ) {
7964				return;
7965			}
7966
7967			if ( isFunction ) {
7968				val = value.call( this, i, jQuery( this ).val() );
7969			} else {
7970				val = value;
7971			}
7972
7973			// Treat null/undefined as ""; convert numbers to string
7974			if ( val == null ) {
7975				val = "";
7976
7977			} else if ( typeof val === "number" ) {
7978				val += "";
7979
7980			} else if ( Array.isArray( val ) ) {
7981				val = jQuery.map( val, function( value ) {
7982					return value == null ? "" : value + "";
7983				} );
7984			}
7985
7986			hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ];
7987
7988			// If set returns undefined, fall back to normal setting
vendor: 8,160 bytes, lines 7989-8307
7989			if ( !hooks || !( "set" in hooks ) || hooks.set( this, val, "value" ) === undefined ) {
7990				this.value = val;
7991			}
7992		} );
7993	}
7994} );
7995
7996jQuery.extend( {
7997	valHooks: {
7998		option: {
7999			get: function( elem ) {
8000
8001				var val = jQuery.find.attr( elem, "value" );
8002				return val != null ?
8003					val :
8004
8005					// Support: IE <=10 - 11 only
8006					// option.text throws exceptions (#14686, #14858)
8007					// Strip and collapse whitespace
8008					// https://html.spec.whatwg.org/#strip-and-collapse-whitespace
8009					stripAndCollapse( jQuery.text( elem ) );
8010			}
8011		},
8012		select: {
8013			get: function( elem ) {
8014				var value, option, i,
8015					options = elem.options,
8016					index = elem.selectedIndex,
8017					one = elem.type === "select-one",
8018					values = one ? null : [],
8019					max = one ? index + 1 : options.length;
8020
8021				if ( index < 0 ) {
8022					i = max;
8023
8024				} else {
8025					i = one ? index : 0;
8026				}
8027
8028				// Loop through all the selected options
8029				for ( ; i < max; i++ ) {
8030					option = options[ i ];
8031
8032					// Support: IE <=9 only
8033					// IE8-9 doesn't update selected after form reset (#2551)
8034					if ( ( option.selected || i === index ) &&
8035
8036							// Don't return options that are disabled or in a disabled optgroup
8037							!option.disabled &&
8038							( !option.parentNode.disabled ||
8039								!nodeName( option.parentNode, "optgroup" ) ) ) {
8040
8041						// Get the specific value for the option
8042						value = jQuery( option ).val();
8043
8044						// We don't need an array for one selects
8045						if ( one ) {
8046							return value;
8047						}
8048
8049						// Multi-Selects return an array
8050						values.push( value );
8051					}
8052				}
8053
8054				return values;
8055			},
8056
8057			set: function( elem, value ) {
8058				var optionSet, option,
8059					options = elem.options,
8060					values = jQuery.makeArray( value ),
8061					i = options.length;
8062
8063				while ( i-- ) {
8064					option = options[ i ];
8065
8066					/* eslint-disable no-cond-assign */
8067
8068					if ( option.selected =
8069						jQuery.inArray( jQuery.valHooks.option.get( option ), values ) > -1
8070					) {
8071						optionSet = true;
8072					}
8073
8074					/* eslint-enable no-cond-assign */
8075				}
8076
8077				// Force browsers to behave consistently when non-matching value is set
8078				if ( !optionSet ) {
8079					elem.selectedIndex = -1;
8080				}
8081				return values;
8082			}
8083		}
8084	}
8085} );
8086
8087// Radios and checkboxes getter/setter
8088jQuery.each( [ "radio", "checkbox" ], function() {
8089	jQuery.valHooks[ this ] = {
8090		set: function( elem, value ) {
8091			if ( Array.isArray( value ) ) {
8092				return ( elem.checked = jQuery.inArray( jQuery( elem ).val(), value ) > -1 );
8093			}
8094		}
8095	};
8096	if ( !support.checkOn ) {
8097		jQuery.valHooks[ this ].get = function( elem ) {
8098			return elem.getAttribute( "value" ) === null ? "on" : elem.value;
8099		};
8100	}
8101} );
8102
8103
8104
8105
8106// Return jQuery for attributes-only inclusion
8107
8108
8109var rfocusMorph = /^(?:focusinfocus|focusoutblur)$/;
8110
8111jQuery.extend( jQuery.event, {
8112
8113	trigger: function( event, data, elem, onlyHandlers ) {
8114
8115		var i, cur, tmp, bubbleType, ontype, handle, special,
8116			eventPath = [ elem || document ],
8117			type = hasOwn.call( event, "type" ) ? event.type : event,
8118			namespaces = hasOwn.call( event, "namespace" ) ? event.namespace.split( "." ) : [];
8119
8120		cur = tmp = elem = elem || document;
8121
8122		// Don't do events on text and comment nodes
8123		if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
8124			return;
8125		}
8126
8127		// focus/blur morphs to focusin/out; ensure we're not firing them right now
8128		if ( rfocusMorph.test( type + jQuery.event.triggered ) ) {
8129			return;
8130		}
8131
8132		if ( type.indexOf( "." ) > -1 ) {
8133
8134			// Namespaced trigger; create a regexp to match event type in handle()
8135			namespaces = type.split( "." );
8136			type = namespaces.shift();
8137			namespaces.sort();
8138		}
8139		ontype = type.indexOf( ":" ) < 0 && "on" + type;
8140
8141		// Caller can pass in a jQuery.Event object, Object, or just an event type string
8142		event = event[ jQuery.expando ] ?
8143			event :
8144			new jQuery.Event( type, typeof event === "object" && event );
8145
8146		// Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true)
8147		event.isTrigger = onlyHandlers ? 2 : 3;
8148		event.namespace = namespaces.join( "." );
8149		event.rnamespace = event.namespace ?
8150			new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ) :
8151			null;
8152
8153		// Clean up the event in case it is being reused
8154		event.result = undefined;
8155		if ( !event.target ) {
8156			event.target = elem;
8157		}
8158
8159		// Clone any incoming data and prepend the event, creating the handler arg list
8160		data = data == null ?
8161			[ event ] :
8162			jQuery.makeArray( data, [ event ] );
8163
8164		// Allow special events to draw outside the lines
8165		special = jQuery.event.special[ type ] || {};
8166		if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) {
8167			return;
8168		}
8169
8170		// Determine event propagation path in advance, per W3C events spec (#9951)
8171		// Bubble up to document, then to window; watch for a global ownerDocument var (#9724)
8172		if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) {
8173
8174			bubbleType = special.delegateType || type;
8175			if ( !rfocusMorph.test( bubbleType + type ) ) {
8176				cur = cur.parentNode;
8177			}
8178			for ( ; cur; cur = cur.parentNode ) {
8179				eventPath.push( cur );
8180				tmp = cur;
8181			}
8182
8183			// Only add window if we got to document (e.g., not plain obj or detached DOM)
8184			if ( tmp === ( elem.ownerDocument || document ) ) {
8185				eventPath.push( tmp.defaultView || tmp.parentWindow || window );
8186			}
8187		}
8188
8189		// Fire handlers on the event path
8190		i = 0;
8191		while ( ( cur = eventPath[ i++ ] ) && !event.isPropagationStopped() ) {
8192
8193			event.type = i > 1 ?
8194				bubbleType :
8195				special.bindType || type;
8196
8197			// jQuery handler
8198			handle = ( dataPriv.get( cur, "events" ) || {} )[ event.type ] &&
8199				dataPriv.get( cur, "handle" );
8200			if ( handle ) {
8201				handle.apply( cur, data );
8202			}
8203
8204			// Native handler
8205			handle = ontype && cur[ ontype ];
8206			if ( handle && handle.apply && acceptData( cur ) ) {
8207				event.result = handle.apply( cur, data );
8208				if ( event.result === false ) {
8209					event.preventDefault();
8210				}
8211			}
8212		}
8213		event.type = type;
8214
8215		// If nobody prevented the default action, do it now
8216		if ( !onlyHandlers && !event.isDefaultPrevented() ) {
8217
8218			if ( ( !special._default ||
8219				special._default.apply( eventPath.pop(), data ) === false ) &&
8220				acceptData( elem ) ) {
8221
8222				// Call a native DOM method on the target with the same name as the event.
8223				// Don't do default actions on window, that's where global variables be (#6170)
8224				if ( ontype && jQuery.isFunction( elem[ type ] ) && !jQuery.isWindow( elem ) ) {
8225
8226					// Don't re-trigger an onFOO event when we call its FOO() method
8227					tmp = elem[ ontype ];
8228
8229					if ( tmp ) {
8230						elem[ ontype ] = null;
8231					}
8232
8233					// Prevent re-triggering of the same event, since we already bubbled it above
8234					jQuery.event.triggered = type;
8235					elem[ type ]();
8236					jQuery.event.triggered = undefined;
8237
8238					if ( tmp ) {
8239						elem[ ontype ] = tmp;
8240					}
8241				}
8242			}
8243		}
8244
8245		return event.result;
8246	},
8247
8248	// Piggyback on a donor event to simulate a different one
8249	// Used only for `focus(in | out)` events
8250	simulate: function( type, elem, event ) {
8251		var e = jQuery.extend(
8252			new jQuery.Event(),
8253			event,
8254			{
8255				type: type,
8256				isSimulated: true
8257			}
8258		);
8259
8260		jQuery.event.trigger( e, null, elem );
8261	}
8262
8263} );
8264
8265jQuery.fn.extend( {
8266
8267	trigger: function( type, data ) {
8268		return this.each( function() {
8269			jQuery.event.trigger( type, data, this );
8270		} );
8271	},
8272	triggerHandler: function( type, data ) {
8273		var elem = this[ 0 ];
8274		if ( elem ) {
8275			return jQuery.event.trigger( type, data, elem, true );
8276		}
8277	}
8278} );
8279
8280
8281jQuery.each( ( "blur focus focusin focusout resize scroll click dblclick " +
8282	"mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " +
8283	"change select submit keydown keypress keyup contextmenu" ).split( " " ),
8284	function( i, name ) {
8285
8286	// Handle event binding
8287	jQuery.fn[ name ] = function( data, fn ) {
8288		return arguments.length > 0 ?
8289			this.on( name, null, data, fn ) :
8290			this.trigger( name );
8291	};
8292} );
8293
8294jQuery.fn.extend( {
8295	hover: function( fnOver, fnOut ) {
8296		return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );
8297	}
8298} );
8299
8300
8301
8302
8303support.focusin = "onfocusin" in window;
8304
8305
8306// Support: Firefox <=44
8307// Firefox doesn't have focus(in | out) events
vendor: 4,174 bytes, lines 8308-8471
8308// Related ticket - https://bugzilla.mozilla.org/show_bug.cgi?id=687787
8309//
8310// Support: Chrome <=48 - 49, Safari <=9.0 - 9.1
8311// focus(in | out) events fire after focus & blur events,
8312// which is spec violation - http://www.w3.org/TR/DOM-Level-3-Events/#events-focusevent-event-order
8313// Related ticket - https://bugs.chromium.org/p/chromium/issues/detail?id=449857
8314if ( !support.focusin ) {
8315	jQuery.each( { focus: "focusin", blur: "focusout" }, function( orig, fix ) {
8316
8317		// Attach a single capturing handler on the document while someone wants focusin/focusout
8318		var handler = function( event ) {
8319			jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ) );
8320		};
8321
8322		jQuery.event.special[ fix ] = {
8323			setup: function() {
8324				var doc = this.ownerDocument || this,
8325					attaches = dataPriv.access( doc, fix );
8326
8327				if ( !attaches ) {
8328					doc.addEventListener( orig, handler, true );
8329				}
8330				dataPriv.access( doc, fix, ( attaches || 0 ) + 1 );
8331			},
8332			teardown: function() {
8333				var doc = this.ownerDocument || this,
8334					attaches = dataPriv.access( doc, fix ) - 1;
8335
8336				if ( !attaches ) {
8337					doc.removeEventListener( orig, handler, true );
8338					dataPriv.remove( doc, fix );
8339
8340				} else {
8341					dataPriv.access( doc, fix, attaches );
8342				}
8343			}
8344		};
8345	} );
8346}
8347var location = window.location;
8348
8349var nonce = jQuery.now();
8350
8351var rquery = ( /\?/ );
8352
8353
8354
8355// Cross-browser xml parsing
8356jQuery.parseXML = function( data ) {
8357	var xml;
8358	if ( !data || typeof data !== "string" ) {
8359		return null;
8360	}
8361
8362	// Support: IE 9 - 11 only
8363	// IE throws on parseFromString with invalid input.
8364	try {
8365		xml = ( new window.DOMParser() ).parseFromString( data, "text/xml" );
8366	} catch ( e ) {
8367		xml = undefined;
8368	}
8369
8370	if ( !xml || xml.getElementsByTagName( "parsererror" ).length ) {
8371		jQuery.error( "Invalid XML: " + data );
8372	}
8373	return xml;
8374};
8375
8376
8377var
8378	rbracket = /\[\]$/,
8379	rCRLF = /\r?\n/g,
8380	rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i,
8381	rsubmittable = /^(?:input|select|textarea|keygen)/i;
8382
8383function buildParams( prefix, obj, traditional, add ) {
8384	var name;
8385
8386	if ( Array.isArray( obj ) ) {
8387
8388		// Serialize array item.
8389		jQuery.each( obj, function( i, v ) {
8390			if ( traditional || rbracket.test( prefix ) ) {
8391
8392				// Treat each array item as a scalar.
8393				add( prefix, v );
8394
8395			} else {
8396
8397				// Item is non-scalar (array or object), encode its numeric index.
8398				buildParams(
8399					prefix + "[" + ( typeof v === "object" && v != null ? i : "" ) + "]",
8400					v,
8401					traditional,
8402					add
8403				);
8404			}
8405		} );
8406
8407	} else if ( !traditional && jQuery.type( obj ) === "object" ) {
8408
8409		// Serialize object item.
8410		for ( name in obj ) {
8411			buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add );
8412		}
8413
8414	} else {
8415
8416		// Serialize scalar item.
8417		add( prefix, obj );
8418	}
8419}
8420
8421// Serialize an array of form elements or a set of
8422// key/values into a query string
8423jQuery.param = function( a, traditional ) {
8424	var prefix,
8425		s = [],
8426		add = function( key, valueOrFunction ) {
8427
8428			// If value is a function, invoke it and use its return value
8429			var value = jQuery.isFunction( valueOrFunction ) ?
8430				valueOrFunction() :
8431				valueOrFunction;
8432
8433			s[ s.length ] = encodeURIComponent( key ) + "=" +
8434				encodeURIComponent( value == null ? "" : value );
8435		};
8436
8437	// If an array was passed in, assume that it is an array of form elements.
8438	if ( Array.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) {
8439
8440		// Serialize the form elements
8441		jQuery.each( a, function() {
8442			add( this.name, this.value );
8443		} );
8444
8445	} else {
8446
8447		// If traditional, encode the "old" way (the way 1.3.2 or older
8448		// did it), otherwise encode params recursively.
8449		for ( prefix in a ) {
8450			buildParams( prefix, a[ prefix ], traditional, add );
8451		}
8452	}
8453
8454	// Return the resulting serialization
8455	return s.join( "&" );
8456};
8457
8458jQuery.fn.extend( {
8459	serialize: function() {
8460		return jQuery.param( this.serializeArray() );
8461	},
8462	serializeArray: function() {
8463		return this.map( function() {
8464
8465			// Can add propHook for "elements" to filter or add form elements
8466			var elements = jQuery.prop( this, "elements" );
8467			return elements ? jQuery.makeArray( elements ) : this;
8468		} )
8469		.filter( function() {
8470			var type = this.type;
8471
vendor: 4,939 bytes, lines 8472-8644
8472			// Use .is( ":disabled" ) so that fieldset[disabled] works
8473			return this.name && !jQuery( this ).is( ":disabled" ) &&
8474				rsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) &&
8475				( this.checked || !rcheckableType.test( type ) );
8476		} )
8477		.map( function( i, elem ) {
8478			var val = jQuery( this ).val();
8479
8480			if ( val == null ) {
8481				return null;
8482			}
8483
8484			if ( Array.isArray( val ) ) {
8485				return jQuery.map( val, function( val ) {
8486					return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
8487				} );
8488			}
8489
8490			return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
8491		} ).get();
8492	}
8493} );
8494
8495
8496var
8497	r20 = /%20/g,
8498	rhash = /#.*$/,
8499	rantiCache = /([?&])_=[^&]*/,
8500	rheaders = /^(.*?):[ \t]*([^\r\n]*)$/mg,
8501
8502	// #7653, #8125, #8152: local protocol detection
8503	rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/,
8504	rnoContent = /^(?:GET|HEAD)$/,
8505	rprotocol = /^\/\//,
8506
8507	/* Prefilters
8508	 * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example)
8509	 * 2) These are called:
8510	 *    - BEFORE asking for a transport
8511	 *    - AFTER param serialization (s.data is a string if s.processData is true)
8512	 * 3) key is the dataType
8513	 * 4) the catchall symbol "*" can be used
8514	 * 5) execution will start with transport dataType and THEN continue down to "*" if needed
8515	 */
8516	prefilters = {},
8517
8518	/* Transports bindings
8519	 * 1) key is the dataType
8520	 * 2) the catchall symbol "*" can be used
8521	 * 3) selection will start with transport dataType and THEN go to "*" if needed
8522	 */
8523	transports = {},
8524
8525	// Avoid comment-prolog char sequence (#10098); must appease lint and evade compression
8526	allTypes = "*/".concat( "*" ),
8527
8528	// Anchor tag for parsing the document origin
8529	originAnchor = document.createElement( "a" );
8530	originAnchor.href = location.href;
8531
8532// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport
8533function addToPrefiltersOrTransports( structure ) {
8534
8535	// dataTypeExpression is optional and defaults to "*"
8536	return function( dataTypeExpression, func ) {
8537
8538		if ( typeof dataTypeExpression !== "string" ) {
8539			func = dataTypeExpression;
8540			dataTypeExpression = "*";
8541		}
8542
8543		var dataType,
8544			i = 0,
8545			dataTypes = dataTypeExpression.toLowerCase().match( rnothtmlwhite ) || [];
8546
8547		if ( jQuery.isFunction( func ) ) {
8548
8549			// For each dataType in the dataTypeExpression
8550			while ( ( dataType = dataTypes[ i++ ] ) ) {
8551
8552				// Prepend if requested
8553				if ( dataType[ 0 ] === "+" ) {
8554					dataType = dataType.slice( 1 ) || "*";
8555					( structure[ dataType ] = structure[ dataType ] || [] ).unshift( func );
8556
8557				// Otherwise append
8558				} else {
8559					( structure[ dataType ] = structure[ dataType ] || [] ).push( func );
8560				}
8561			}
8562		}
8563	};
8564}
8565
8566// Base inspection function for prefilters and transports
8567function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) {
8568
8569	var inspected = {},
8570		seekingTransport = ( structure === transports );
8571
8572	function inspect( dataType ) {
8573		var selected;
8574		inspected[ dataType ] = true;
8575		jQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) {
8576			var dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR );
8577			if ( typeof dataTypeOrTransport === "string" &&
8578				!seekingTransport && !inspected[ dataTypeOrTransport ] ) {
8579
8580				options.dataTypes.unshift( dataTypeOrTransport );
8581				inspect( dataTypeOrTransport );
8582				return false;
8583			} else if ( seekingTransport ) {
8584				return !( selected = dataTypeOrTransport );
8585			}
8586		} );
8587		return selected;
8588	}
8589
8590	return inspect( options.dataTypes[ 0 ] ) || !inspected[ "*" ] && inspect( "*" );
8591}
8592
8593// A special extend for ajax options
8594// that takes "flat" options (not to be deep extended)
8595// Fixes #9887
8596function ajaxExtend( target, src ) {
8597	var key, deep,
8598		flatOptions = jQuery.ajaxSettings.flatOptions || {};
8599
8600	for ( key in src ) {
8601		if ( src[ key ] !== undefined ) {
8602			( flatOptions[ key ] ? target : ( deep || ( deep = {} ) ) )[ key ] = src[ key ];
8603		}
8604	}
8605	if ( deep ) {
8606		jQuery.extend( true, target, deep );
8607	}
8608
8609	return target;
8610}
8611
8612/* Handles responses to an ajax request:
8613 * - finds the right dataType (mediates between content-type and expected dataType)
8614 * - returns the corresponding response
8615 */
8616function ajaxHandleResponses( s, jqXHR, responses ) {
8617
8618	var ct, type, finalDataType, firstDataType,
8619		contents = s.contents,
8620		dataTypes = s.dataTypes;
8621
8622	// Remove auto dataType and get content-type in the process
8623	while ( dataTypes[ 0 ] === "*" ) {
8624		dataTypes.shift();
8625		if ( ct === undefined ) {
8626			ct = s.mimeType || jqXHR.getResponseHeader( "Content-Type" );
8627		}
8628	}
8629
8630	// Check if we're dealing with a known content-type
8631	if ( ct ) {
8632		for ( type in contents ) {
8633			if ( contents[ type ] && contents[ type ].test( ct ) ) {
8634				dataTypes.unshift( type );
8635				break;
8636			}
8637		}
8638	}
8639
8640	// Check to see if we have a response for the expected dataType
8641	if ( dataTypes[ 0 ] in responses ) {
8642		finalDataType = dataTypes[ 0 ];
8643	} else {
8644
vendor: 18,932 bytes, lines 8645-9402
8645		// Try convertible dataTypes
8646		for ( type in responses ) {
8647			if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[ 0 ] ] ) {
8648				finalDataType = type;
8649				break;
8650			}
8651			if ( !firstDataType ) {
8652				firstDataType = type;
8653			}
8654		}
8655
8656		// Or just use first one
8657		finalDataType = finalDataType || firstDataType;
8658	}
8659
8660	// If we found a dataType
8661	// We add the dataType to the list if needed
8662	// and return the corresponding response
8663	if ( finalDataType ) {
8664		if ( finalDataType !== dataTypes[ 0 ] ) {
8665			dataTypes.unshift( finalDataType );
8666		}
8667		return responses[ finalDataType ];
8668	}
8669}
8670
8671/* Chain conversions given the request and the original response
8672 * Also sets the responseXXX fields on the jqXHR instance
8673 */
8674function ajaxConvert( s, response, jqXHR, isSuccess ) {
8675	var conv2, current, conv, tmp, prev,
8676		converters = {},
8677
8678		// Work with a copy of dataTypes in case we need to modify it for conversion
8679		dataTypes = s.dataTypes.slice();
8680
8681	// Create converters map with lowercased keys
8682	if ( dataTypes[ 1 ] ) {
8683		for ( conv in s.converters ) {
8684			converters[ conv.toLowerCase() ] = s.converters[ conv ];
8685		}
8686	}
8687
8688	current = dataTypes.shift();
8689
8690	// Convert to each sequential dataType
8691	while ( current ) {
8692
8693		if ( s.responseFields[ current ] ) {
8694			jqXHR[ s.responseFields[ current ] ] = response;
8695		}
8696
8697		// Apply the dataFilter if provided
8698		if ( !prev && isSuccess && s.dataFilter ) {
8699			response = s.dataFilter( response, s.dataType );
8700		}
8701
8702		prev = current;
8703		current = dataTypes.shift();
8704
8705		if ( current ) {
8706
8707			// There's only work to do if current dataType is non-auto
8708			if ( current === "*" ) {
8709
8710				current = prev;
8711
8712			// Convert response if prev dataType is non-auto and differs from current
8713			} else if ( prev !== "*" && prev !== current ) {
8714
8715				// Seek a direct converter
8716				conv = converters[ prev + " " + current ] || converters[ "* " + current ];
8717
8718				// If none found, seek a pair
8719				if ( !conv ) {
8720					for ( conv2 in converters ) {
8721
8722						// If conv2 outputs current
8723						tmp = conv2.split( " " );
8724						if ( tmp[ 1 ] === current ) {
8725
8726							// If prev can be converted to accepted input
8727							conv = converters[ prev + " " + tmp[ 0 ] ] ||
8728								converters[ "* " + tmp[ 0 ] ];
8729							if ( conv ) {
8730
8731								// Condense equivalence converters
8732								if ( conv === true ) {
8733									conv = converters[ conv2 ];
8734
8735								// Otherwise, insert the intermediate dataType
8736								} else if ( converters[ conv2 ] !== true ) {
8737									current = tmp[ 0 ];
8738									dataTypes.unshift( tmp[ 1 ] );
8739								}
8740								break;
8741							}
8742						}
8743					}
8744				}
8745
8746				// Apply converter (if not an equivalence)
8747				if ( conv !== true ) {
8748
8749					// Unless errors are allowed to bubble, catch and return them
8750					if ( conv && s.throws ) {
8751						response = conv( response );
8752					} else {
8753						try {
8754							response = conv( response );
8755						} catch ( e ) {
8756							return {
8757								state: "parsererror",
8758								error: conv ? e : "No conversion from " + prev + " to " + current
8759							};
8760						}
8761					}
8762				}
8763			}
8764		}
8765	}
8766
8767	return { state: "success", data: response };
8768}
8769
8770jQuery.extend( {
8771
8772	// Counter for holding the number of active queries
8773	active: 0,
8774
8775	// Last-Modified header cache for next request
8776	lastModified: {},
8777	etag: {},
8778
8779	ajaxSettings: {
8780		url: location.href,
8781		type: "GET",
8782		isLocal: rlocalProtocol.test( location.protocol ),
8783		global: true,
8784		processData: true,
8785		async: true,
8786		contentType: "application/x-www-form-urlencoded; charset=UTF-8",
8787
8788		/*
8789		timeout: 0,
8790		data: null,
8791		dataType: null,
8792		username: null,
8793		password: null,
8794		cache: null,
8795		throws: false,
8796		traditional: false,
8797		headers: {},
8798		*/
8799
8800		accepts: {
8801			"*": allTypes,
8802			text: "text/plain",
8803			html: "text/html",
8804			xml: "application/xml, text/xml",
8805			json: "application/json, text/javascript"
8806		},
8807
8808		contents: {
8809			xml: /\bxml\b/,
8810			html: /\bhtml/,
8811			json: /\bjson\b/
8812		},
8813
8814		responseFields: {
8815			xml: "responseXML",
8816			text: "responseText",
8817			json: "responseJSON"
8818		},
8819
8820		// Data converters
8821		// Keys separate source (or catchall "*") and destination types with a single space
8822		converters: {
8823
8824			// Convert anything to text
8825			"* text": String,
8826
8827			// Text to html (true = no transformation)
8828			"text html": true,
8829
8830			// Evaluate text as a json expression
8831			"text json": JSON.parse,
8832
8833			// Parse text as xml
8834			"text xml": jQuery.parseXML
8835		},
8836
8837		// For options that shouldn't be deep extended:
8838		// you can add your own custom options here if
8839		// and when you create one that shouldn't be
8840		// deep extended (see ajaxExtend)
8841		flatOptions: {
8842			url: true,
8843			context: true
8844		}
8845	},
8846
8847	// Creates a full fledged settings object into target
8848	// with both ajaxSettings and settings fields.
8849	// If target is omitted, writes into ajaxSettings.
8850	ajaxSetup: function( target, settings ) {
8851		return settings ?
8852
8853			// Building a settings object
8854			ajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) :
8855
8856			// Extending ajaxSettings
8857			ajaxExtend( jQuery.ajaxSettings, target );
8858	},
8859
8860	ajaxPrefilter: addToPrefiltersOrTransports( prefilters ),
8861	ajaxTransport: addToPrefiltersOrTransports( transports ),
8862
8863	// Main method
8864	ajax: function( url, options ) {
8865
8866		// If url is an object, simulate pre-1.5 signature
8867		if ( typeof url === "object" ) {
8868			options = url;
8869			url = undefined;
8870		}
8871
8872		// Force options to be an object
8873		options = options || {};
8874
8875		var transport,
8876
8877			// URL without anti-cache param
8878			cacheURL,
8879
8880			// Response headers
8881			responseHeadersString,
8882			responseHeaders,
8883
8884			// timeout handle
8885			timeoutTimer,
8886
8887			// Url cleanup var
8888			urlAnchor,
8889
8890			// Request state (becomes false upon send and true upon completion)
8891			completed,
8892
8893			// To know if global events are to be dispatched
8894			fireGlobals,
8895
8896			// Loop variable
8897			i,
8898
8899			// uncached part of the url
8900			uncached,
8901
8902			// Create the final options object
8903			s = jQuery.ajaxSetup( {}, options ),
8904
8905			// Callbacks context
8906			callbackContext = s.context || s,
8907
8908			// Context for global events is callbackContext if it is a DOM node or jQuery collection
8909			globalEventContext = s.context &&
8910				( callbackContext.nodeType || callbackContext.jquery ) ?
8911					jQuery( callbackContext ) :
8912					jQuery.event,
8913
8914			// Deferreds
8915			deferred = jQuery.Deferred(),
8916			completeDeferred = jQuery.Callbacks( "once memory" ),
8917
8918			// Status-dependent callbacks
8919			statusCode = s.statusCode || {},
8920
8921			// Headers (they are sent all at once)
8922			requestHeaders = {},
8923			requestHeadersNames = {},
8924
8925			// Default abort message
8926			strAbort = "canceled",
8927
8928			// Fake xhr
8929			jqXHR = {
8930				readyState: 0,
8931
8932				// Builds headers hashtable if needed
8933				getResponseHeader: function( key ) {
8934					var match;
8935					if ( completed ) {
8936						if ( !responseHeaders ) {
8937							responseHeaders = {};
8938							while ( ( match = rheaders.exec( responseHeadersString ) ) ) {
8939								responseHeaders[ match[ 1 ].toLowerCase() ] = match[ 2 ];
8940							}
8941						}
8942						match = responseHeaders[ key.toLowerCase() ];
8943					}
8944					return match == null ? null : match;
8945				},
8946
8947				// Raw string
8948				getAllResponseHeaders: function() {
8949					return completed ? responseHeadersString : null;
8950				},
8951
8952				// Caches the header
8953				setRequestHeader: function( name, value ) {
8954					if ( completed == null ) {
8955						name = requestHeadersNames[ name.toLowerCase() ] =
8956							requestHeadersNames[ name.toLowerCase() ] || name;
8957						requestHeaders[ name ] = value;
8958					}
8959					return this;
8960				},
8961
8962				// Overrides response content-type header
8963				overrideMimeType: function( type ) {
8964					if ( completed == null ) {
8965						s.mimeType = type;
8966					}
8967					return this;
8968				},
8969
8970				// Status-dependent callbacks
8971				statusCode: function( map ) {
8972					var code;
8973					if ( map ) {
8974						if ( completed ) {
8975
8976							// Execute the appropriate callbacks
8977							jqXHR.always( map[ jqXHR.status ] );
8978						} else {
8979
8980							// Lazy-add the new callbacks in a way that preserves old ones
8981							for ( code in map ) {
8982								statusCode[ code ] = [ statusCode[ code ], map[ code ] ];
8983							}
8984						}
8985					}
8986					return this;
8987				},
8988
8989				// Cancel the request
8990				abort: function( statusText ) {
8991					var finalText = statusText || strAbort;
8992					if ( transport ) {
8993						transport.abort( finalText );
8994					}
8995					done( 0, finalText );
8996					return this;
8997				}
8998			};
8999
9000		// Attach deferreds
9001		deferred.promise( jqXHR );
9002
9003		// Add protocol if not provided (prefilters might expect it)
9004		// Handle falsy url in the settings object (#10093: consistency with old signature)
9005		// We also use the url parameter if available
9006		s.url = ( ( url || s.url || location.href ) + "" )
9007			.replace( rprotocol, location.protocol + "//" );
9008
9009		// Alias method option to type as per ticket #12004
9010		s.type = options.method || options.type || s.method || s.type;
9011
9012		// Extract dataTypes list
9013		s.dataTypes = ( s.dataType || "*" ).toLowerCase().match( rnothtmlwhite ) || [ "" ];
9014
9015		// A cross-domain request is in order when the origin doesn't match the current origin.
9016		if ( s.crossDomain == null ) {
9017			urlAnchor = document.createElement( "a" );
9018
9019			// Support: IE <=8 - 11, Edge 12 - 13
9020			// IE throws exception on accessing the href property if url is malformed,
9021			// e.g. http://example.com:80x/
9022			try {
9023				urlAnchor.href = s.url;
9024
9025				// Support: IE <=8 - 11 only
9026				// Anchor's host property isn't correctly set when s.url is relative
9027				urlAnchor.href = urlAnchor.href;
9028				s.crossDomain = originAnchor.protocol + "//" + originAnchor.host !==
9029					urlAnchor.protocol + "//" + urlAnchor.host;
9030			} catch ( e ) {
9031
9032				// If there is an error parsing the URL, assume it is crossDomain,
9033				// it can be rejected by the transport if it is invalid
9034				s.crossDomain = true;
9035			}
9036		}
9037
9038		// Convert data if not already a string
9039		if ( s.data && s.processData && typeof s.data !== "string" ) {
9040			s.data = jQuery.param( s.data, s.traditional );
9041		}
9042
9043		// Apply prefilters
9044		inspectPrefiltersOrTransports( prefilters, s, options, jqXHR );
9045
9046		// If request was aborted inside a prefilter, stop there
9047		if ( completed ) {
9048			return jqXHR;
9049		}
9050
9051		// We can fire global events as of now if asked to
9052		// Don't fire events if jQuery.event is undefined in an AMD-usage scenario (#15118)
9053		fireGlobals = jQuery.event && s.global;
9054
9055		// Watch for a new set of requests
9056		if ( fireGlobals && jQuery.active++ === 0 ) {
9057			jQuery.event.trigger( "ajaxStart" );
9058		}
9059
9060		// Uppercase the type
9061		s.type = s.type.toUpperCase();
9062
9063		// Determine if request has content
9064		s.hasContent = !rnoContent.test( s.type );
9065
9066		// Save the URL in case we're toying with the If-Modified-Since
9067		// and/or If-None-Match header later on
9068		// Remove hash to simplify url manipulation
9069		cacheURL = s.url.replace( rhash, "" );
9070
9071		// More options handling for requests with no content
9072		if ( !s.hasContent ) {
9073
9074			// Remember the hash so we can put it back
9075			uncached = s.url.slice( cacheURL.length );
9076
9077			// If data is available, append data to url
9078			if ( s.data ) {
9079				cacheURL += ( rquery.test( cacheURL ) ? "&" : "?" ) + s.data;
9080
9081				// #9682: remove data so that it's not used in an eventual retry
9082				delete s.data;
9083			}
9084
9085			// Add or update anti-cache param if needed
9086			if ( s.cache === false ) {
9087				cacheURL = cacheURL.replace( rantiCache, "$1" );
9088				uncached = ( rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + ( nonce++ ) + uncached;
9089			}
9090
9091			// Put hash and anti-cache on the URL that will be requested (gh-1732)
9092			s.url = cacheURL + uncached;
9093
9094		// Change '%20' to '+' if this is encoded form body content (gh-2658)
9095		} else if ( s.data && s.processData &&
9096			( s.contentType || "" ).indexOf( "application/x-www-form-urlencoded" ) === 0 ) {
9097			s.data = s.data.replace( r20, "+" );
9098		}
9099
9100		// Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
9101		if ( s.ifModified ) {
9102			if ( jQuery.lastModified[ cacheURL ] ) {
9103				jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ cacheURL ] );
9104			}
9105			if ( jQuery.etag[ cacheURL ] ) {
9106				jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ cacheURL ] );
9107			}
9108		}
9109
9110		// Set the correct header, if data is being sent
9111		if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) {
9112			jqXHR.setRequestHeader( "Content-Type", s.contentType );
9113		}
9114
9115		// Set the Accepts header for the server, depending on the dataType
9116		jqXHR.setRequestHeader(
9117			"Accept",
9118			s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[ 0 ] ] ?
9119				s.accepts[ s.dataTypes[ 0 ] ] +
9120					( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) :
9121				s.accepts[ "*" ]
9122		);
9123
9124		// Check for headers option
9125		for ( i in s.headers ) {
9126			jqXHR.setRequestHeader( i, s.headers[ i ] );
9127		}
9128
9129		// Allow custom headers/mimetypes and early abort
9130		if ( s.beforeSend &&
9131			( s.beforeSend.call( callbackContext, jqXHR, s ) === false || completed ) ) {
9132
9133			// Abort if not done already and return
9134			return jqXHR.abort();
9135		}
9136
9137		// Aborting is no longer a cancellation
9138		strAbort = "abort";
9139
9140		// Install callbacks on deferreds
9141		completeDeferred.add( s.complete );
9142		jqXHR.done( s.success );
9143		jqXHR.fail( s.error );
9144
9145		// Get transport
9146		transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR );
9147
9148		// If no transport, we auto-abort
9149		if ( !transport ) {
9150			done( -1, "No Transport" );
9151		} else {
9152			jqXHR.readyState = 1;
9153
9154			// Send global event
9155			if ( fireGlobals ) {
9156				globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] );
9157			}
9158
9159			// If request was aborted inside ajaxSend, stop there
9160			if ( completed ) {
9161				return jqXHR;
9162			}
9163
9164			// Timeout
9165			if ( s.async && s.timeout > 0 ) {
9166				timeoutTimer = window.setTimeout( function() {
9167					jqXHR.abort( "timeout" );
9168				}, s.timeout );
9169			}
9170
9171			try {
9172				completed = false;
9173				transport.send( requestHeaders, done );
9174			} catch ( e ) {
9175
9176				// Rethrow post-completion exceptions
9177				if ( completed ) {
9178					throw e;
9179				}
9180
9181				// Propagate others as results
9182				done( -1, e );
9183			}
9184		}
9185
9186		// Callback for when everything is done
9187		function done( status, nativeStatusText, responses, headers ) {
9188			var isSuccess, success, error, response, modified,
9189				statusText = nativeStatusText;
9190
9191			// Ignore repeat invocations
9192			if ( completed ) {
9193				return;
9194			}
9195
9196			completed = true;
9197
9198			// Clear timeout if it exists
9199			if ( timeoutTimer ) {
9200				window.clearTimeout( timeoutTimer );
9201			}
9202
9203			// Dereference transport for early garbage collection
9204			// (no matter how long the jqXHR object will be used)
9205			transport = undefined;
9206
9207			// Cache response headers
9208			responseHeadersString = headers || "";
9209
9210			// Set readyState
9211			jqXHR.readyState = status > 0 ? 4 : 0;
9212
9213			// Determine if successful
9214			isSuccess = status >= 200 && status < 300 || status === 304;
9215
9216			// Get response data
9217			if ( responses ) {
9218				response = ajaxHandleResponses( s, jqXHR, responses );
9219			}
9220
9221			// Convert no matter what (that way responseXXX fields are always set)
9222			response = ajaxConvert( s, response, jqXHR, isSuccess );
9223
9224			// If successful, handle type chaining
9225			if ( isSuccess ) {
9226
9227				// Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
9228				if ( s.ifModified ) {
9229					modified = jqXHR.getResponseHeader( "Last-Modified" );
9230					if ( modified ) {
9231						jQuery.lastModified[ cacheURL ] = modified;
9232					}
9233					modified = jqXHR.getResponseHeader( "etag" );
9234					if ( modified ) {
9235						jQuery.etag[ cacheURL ] = modified;
9236					}
9237				}
9238
9239				// if no content
9240				if ( status === 204 || s.type === "HEAD" ) {
9241					statusText = "nocontent";
9242
9243				// if not modified
9244				} else if ( status === 304 ) {
9245					statusText = "notmodified";
9246
9247				// If we have data, let's convert it
9248				} else {
9249					statusText = response.state;
9250					success = response.data;
9251					error = response.error;
9252					isSuccess = !error;
9253				}
9254			} else {
9255
9256				// Extract error from statusText and normalize for non-aborts
9257				error = statusText;
9258				if ( status || !statusText ) {
9259					statusText = "error";
9260					if ( status < 0 ) {
9261						status = 0;
9262					}
9263				}
9264			}
9265
9266			// Set data for the fake xhr object
9267			jqXHR.status = status;
9268			jqXHR.statusText = ( nativeStatusText || statusText ) + "";
9269
9270			// Success/Error
9271			if ( isSuccess ) {
9272				deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] );
9273			} else {
9274				deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] );
9275			}
9276
9277			// Status-dependent callbacks
9278			jqXHR.statusCode( statusCode );
9279			statusCode = undefined;
9280
9281			if ( fireGlobals ) {
9282				globalEventContext.trigger( isSuccess ? "ajaxSuccess" : "ajaxError",
9283					[ jqXHR, s, isSuccess ? success : error ] );
9284			}
9285
9286			// Complete
9287			completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] );
9288
9289			if ( fireGlobals ) {
9290				globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] );
9291
9292				// Handle the global AJAX counter
9293				if ( !( --jQuery.active ) ) {
9294					jQuery.event.trigger( "ajaxStop" );
9295				}
9296			}
9297		}
9298
9299		return jqXHR;
9300	},
9301
9302	getJSON: function( url, data, callback ) {
9303		return jQuery.get( url, data, callback, "json" );
9304	},
9305
9306	getScript: function( url, callback ) {
9307		return jQuery.get( url, undefined, callback, "script" );
9308	}
9309} );
9310
9311jQuery.each( [ "get", "post" ], function( i, method ) {
9312	jQuery[ method ] = function( url, data, callback, type ) {
9313
9314		// Shift arguments if data argument was omitted
9315		if ( jQuery.isFunction( data ) ) {
9316			type = type || callback;
9317			callback = data;
9318			data = undefined;
9319		}
9320
9321		// The url can be an options object (which then must have .url)
9322		return jQuery.ajax( jQuery.extend( {
9323			url: url,
9324			type: method,
9325			dataType: type,
9326			data: data,
9327			success: callback
9328		}, jQuery.isPlainObject( url ) && url ) );
9329	};
9330} );
9331
9332
9333jQuery._evalUrl = function( url ) {
9334	return jQuery.ajax( {
9335		url: url,
9336
9337		// Make this explicit, since user can override this through ajaxSetup (#11264)
9338		type: "GET",
9339		dataType: "script",
9340		cache: true,
9341		async: false,
9342		global: false,
9343		"throws": true
9344	} );
9345};
9346
9347
9348jQuery.fn.extend( {
9349	wrapAll: function( html ) {
9350		var wrap;
9351
9352		if ( this[ 0 ] ) {
9353			if ( jQuery.isFunction( html ) ) {
9354				html = html.call( this[ 0 ] );
9355			}
9356
9357			// The elements to wrap the target around
9358			wrap = jQuery( html, this[ 0 ].ownerDocument ).eq( 0 ).clone( true );
9359
9360			if ( this[ 0 ].parentNode ) {
9361				wrap.insertBefore( this[ 0 ] );
9362			}
9363
9364			wrap.map( function() {
9365				var elem = this;
9366
9367				while ( elem.firstElementChild ) {
9368					elem = elem.firstElementChild;
9369				}
9370
9371				return elem;
9372			} ).append( this );
9373		}
9374
9375		return this;
9376	},
9377
9378	wrapInner: function( html ) {
9379		if ( jQuery.isFunction( html ) ) {
9380			return this.each( function( i ) {
9381				jQuery( this ).wrapInner( html.call( this, i ) );
9382			} );
9383		}
9384
9385		return this.each( function() {
9386			var self = jQuery( this ),
9387				contents = self.contents();
9388
9389			if ( contents.length ) {
9390				contents.wrapAll( html );
9391
9392			} else {
9393				self.append( html );
9394			}
9395		} );
9396	},
9397
9398	wrap: function( html ) {
9399		var isFunction = jQuery.isFunction( html );
9400
9401		return this.each( function( i ) {
9402			jQuery( this ).wrapAll( i
vendor: 2,399 bytes, lines 9402-9494
9402sFunction ? html.call( this, i ) : html );
9403		} );
9404	},
9405
9406	unwrap: function( selector ) {
9407		this.parent( selector ).not( "body" ).each( function() {
9408			jQuery( this ).replaceWith( this.childNodes );
9409		} );
9410		return this;
9411	}
9412} );
9413
9414
9415jQuery.expr.pseudos.hidden = function( elem ) {
9416	return !jQuery.expr.pseudos.visible( elem );
9417};
9418jQuery.expr.pseudos.visible = function( elem ) {
9419	return !!( elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length );
9420};
9421
9422
9423
9424
9425jQuery.ajaxSettings.xhr = function() {
9426	try {
9427		return new window.XMLHttpRequest();
9428	} catch ( e ) {}
9429};
9430
9431var xhrSuccessStatus = {
9432
9433		// File protocol always yields status code 0, assume 200
9434		0: 200,
9435
9436		// Support: IE <=9 only
9437		// #1450: sometimes IE returns 1223 when it should be 204
9438		1223: 204
9439	},
9440	xhrSupported = jQuery.ajaxSettings.xhr();
9441
9442support.cors = !!xhrSupported && ( "withCredentials" in xhrSupported );
9443support.ajax = xhrSupported = !!xhrSupported;
9444
9445jQuery.ajaxTransport( function( options ) {
9446	var callback, errorCallback;
9447
9448	// Cross domain only allowed if supported through XMLHttpRequest
9449	if ( support.cors || xhrSupported && !options.crossDomain ) {
9450		return {
9451			send: function( headers, complete ) {
9452				var i,
9453					xhr = options.xhr();
9454
9455				xhr.open(
9456					options.type,
9457					options.url,
9458					options.async,
9459					options.username,
9460					options.password
9461				);
9462
9463				// Apply custom fields if provided
9464				if ( options.xhrFields ) {
9465					for ( i in options.xhrFields ) {
9466						xhr[ i ] = options.xhrFields[ i ];
9467					}
9468				}
9469
9470				// Override mime type if needed
9471				if ( options.mimeType && xhr.overrideMimeType ) {
9472					xhr.overrideMimeType( options.mimeType );
9473				}
9474
9475				// X-Requested-With header
9476				// For cross-domain requests, seeing as conditions for a preflight are
9477				// akin to a jigsaw puzzle, we simply never set it to be sure.
9478				// (it can always be set on a per-request basis or even using ajaxSetup)
9479				// For same-domain requests, won't change header if already provided.
9480				if ( !options.crossDomain && !headers[ "X-Requested-With" ] ) {
9481					headers[ "X-Requested-With" ] = "XMLHttpRequest";
9482				}
9483
9484				// Set headers
9485				for ( i in headers ) {
9486					xhr.setRequestHeader( i, headers[ i ] );
9487				}
9488
9489				// Callback
9490				callback = function( type ) {
9491					return function() {
9492						if ( callback ) {
9493							callback = errorCallback = xhr.onload =
9494								xhr.onerror = xhr.onabort = xhr.on
vendor: 5,102 bytes, lines 9494-9699
9494readystatechange = null;
9495
9496							if ( type === "abort" ) {
9497								xhr.abort();
9498							} else if ( type === "error" ) {
9499
9500								// Support: IE <=9 only
9501								// On a manual native abort, IE9 throws
9502								// errors on any property access that is not readyState
9503								if ( typeof xhr.status !== "number" ) {
9504									complete( 0, "error" );
9505								} else {
9506									complete(
9507
9508										// File: protocol always yields status 0; see #8605, #14207
9509										xhr.status,
9510										xhr.statusText
9511									);
9512								}
9513							} else {
9514								complete(
9515									xhrSuccessStatus[ xhr.status ] || xhr.status,
9516									xhr.statusText,
9517
9518									// Support: IE <=9 only
9519									// IE9 has no XHR2 but throws on binary (trac-11426)
9520									// For XHR2 non-text, let the caller handle it (gh-2498)
9521									( xhr.responseType || "text" ) !== "text"  ||
9522									typeof xhr.responseText !== "string" ?
9523										{ binary: xhr.response } :
9524										{ text: xhr.responseText },
9525									xhr.getAllResponseHeaders()
9526								);
9527							}
9528						}
9529					};
9530				};
9531
9532				// Listen to events
9533				xhr.onload = callback();
9534				errorCallback = xhr.onerror = callback( "error" );
9535
9536				// Support: IE 9 only
9537				// Use onreadystatechange to replace onabort
9538				// to handle uncaught aborts
9539				if ( xhr.onabort !== undefined ) {
9540					xhr.onabort = errorCallback;
9541				} else {
9542					xhr.onreadystatechange = function() {
9543
9544						// Check readyState before timeout as it changes
9545						if ( xhr.readyState === 4 ) {
9546
9547							// Allow onerror to be called first,
9548							// but that will not handle a native abort
9549							// Also, save errorCallback to a variable
9550							// as xhr.onerror cannot be accessed
9551							window.setTimeout( function() {
9552								if ( callback ) {
9553									errorCallback();
9554								}
9555							} );
9556						}
9557					};
9558				}
9559
9560				// Create the abort callback
9561				callback = callback( "abort" );
9562
9563				try {
9564
9565					// Do send the request (this may raise an exception)
9566					xhr.send( options.hasContent && options.data || null );
9567				} catch ( e ) {
9568
9569					// #14683: Only rethrow if this hasn't been notified as an error yet
9570					if ( callback ) {
9571						throw e;
9572					}
9573				}
9574			},
9575
9576			abort: function() {
9577				if ( callback ) {
9578					callback();
9579				}
9580			}
9581		};
9582	}
9583} );
9584
9585
9586
9587
9588// Prevent auto-execution of scripts when no explicit dataType was provided (See gh-2432)
9589jQuery.ajaxPrefilter( function( s ) {
9590	if ( s.crossDomain ) {
9591		s.contents.script = false;
9592	}
9593} );
9594
9595// Install script dataType
9596jQuery.ajaxSetup( {
9597	accepts: {
9598		script: "text/javascript, application/javascript, " +
9599			"application/ecmascript, application/x-ecmascript"
9600	},
9601	contents: {
9602		script: /\b(?:java|ecma)script\b/
9603	},
9604	converters: {
9605		"text script": function( text ) {
9606			jQuery.globalEval( text );
9607			return text;
9608		}
9609	}
9610} );
9611
9612// Handle cache's special case and crossDomain
9613jQuery.ajaxPrefilter( "script", function( s ) {
9614	if ( s.cache === undefined ) {
9615		s.cache = false;
9616	}
9617	if ( s.crossDomain ) {
9618		s.type = "GET";
9619	}
9620} );
9621
9622// Bind script tag hack transport
9623jQuery.ajaxTransport( "script", function( s ) {
9624
9625	// This transport only deals with cross domain requests
9626	if ( s.crossDomain ) {
9627		var script, callback;
9628		return {
9629			send: function( _, complete ) {
9630				script = jQuery( "<script>" ).prop( {
9631					charset: s.scriptCharset,
9632					src: s.url
9633				} ).on(
9634					"load error",
9635					callback = function( evt ) {
9636						script.remove();
9637						callback = null;
9638						if ( evt ) {
9639							complete( evt.type === "error" ? 404 : 200, evt.type );
9640						}
9641					}
9642				);
9643
9644				// Use native DOM manipulation to avoid our domManip AJAX trickery
9645				document.head.appendChild( script[ 0 ] );
9646			},
9647			abort: function() {
9648				if ( callback ) {
9649					callback();
9650				}
9651			}
9652		};
9653	}
9654} );
9655
9656
9657
9658
9659var oldCallbacks = [],
9660	rjsonp = /(=)\?(?=&|$)|\?\?/;
9661
9662// Default jsonp settings
9663jQuery.ajaxSetup( {
9664	jsonp: "callback",
9665	jsonpCallback: function() {
9666		var callback = oldCallbacks.pop() || ( jQuery.expando + "_" + ( nonce++ ) );
9667		this[ callback ] = true;
9668		return callback;
9669	}
9670} );
9671
9672// Detect, normalize options and install callbacks for jsonp requests
9673jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) {
9674
9675	var callbackName, overwritten, responseContainer,
9676		jsonProp = s.jsonp !== false && ( rjsonp.test( s.url ) ?
9677			"url" :
9678			typeof s.data === "string" &&
9679				( s.contentType || "" )
9680					.indexOf( "application/x-www-form-urlencoded" ) === 0 &&
9681				rjsonp.test( s.data ) && "data"
9682		);
9683
9684	// Handle iff the expected data type is "jsonp" or we have a parameter to set
9685	if ( jsonProp || s.dataTypes[ 0 ] === "jsonp" ) {
9686
9687		// Get callback name, remembering preexisting value associated with it
9688		callbackName = s.jsonpCallback = jQuery.isFunction( s.jsonpCallback ) ?
9689			s.jsonpCallback() :
9690			s.jsonpCallback;
9691
9692		// Insert callback into url or form data
9693		if ( jsonProp ) {
9694			s[ jsonProp ] = s[ jsonProp ].replace( rjsonp, "$1" + callbackName );
9695		} else if ( s.jsonp !== false ) {
9696			s.url += ( rquery.test( s.url ) ? "&" : "?" ) + s.jsonp + "=" + callbackName;
9697		}
9698
9699		// Use data converter to retrieve json after script execution
vendor: 2,994 bytes, lines 9700-9809
9700		s.converters[ "script json" ] = function() {
9701			if ( !responseContainer ) {
9702				jQuery.error( callbackName + " was not called" );
9703			}
9704			return responseContainer[ 0 ];
9705		};
9706
9707		// Force json dataType
9708		s.dataTypes[ 0 ] = "json";
9709
9710		// Install callback
9711		overwritten = window[ callbackName ];
9712		window[ callbackName ] = function() {
9713			responseContainer = arguments;
9714		};
9715
9716		// Clean-up function (fires after converters)
9717		jqXHR.always( function() {
9718
9719			// If previous value didn't exist - remove it
9720			if ( overwritten === undefined ) {
9721				jQuery( window ).removeProp( callbackName );
9722
9723			// Otherwise restore preexisting value
9724			} else {
9725				window[ callbackName ] = overwritten;
9726			}
9727
9728			// Save back as free
9729			if ( s[ callbackName ] ) {
9730
9731				// Make sure that re-using the options doesn't screw things around
9732				s.jsonpCallback = originalSettings.jsonpCallback;
9733
9734				// Save the callback name for future use
9735				oldCallbacks.push( callbackName );
9736			}
9737
9738			// Call if it was a function and we have a response
9739			if ( responseContainer && jQuery.isFunction( overwritten ) ) {
9740				overwritten( responseContainer[ 0 ] );
9741			}
9742
9743			responseContainer = overwritten = undefined;
9744		} );
9745
9746		// Delegate to script
9747		return "script";
9748	}
9749} );
9750
9751
9752
9753
9754// Support: Safari 8 only
9755// In Safari 8 documents created via document.implementation.createHTMLDocument
9756// collapse sibling forms: the second one becomes a child of the first one.
9757// Because of that, this security measure has to be disabled in Safari 8.
9758// https://bugs.webkit.org/show_bug.cgi?id=137337
9759support.createHTMLDocument = ( function() {
9760	var body = document.implementation.createHTMLDocument( "" ).body;
9761	body.innerHTML = "<form></form><form></form>";
9762	return body.childNodes.length === 2;
9763} )();
9764
9765
9766// Argument "data" should be string of html
9767// context (optional): If specified, the fragment will be created in this context,
9768// defaults to document
9769// keepScripts (optional): If true, will include scripts passed in the html string
9770jQuery.parseHTML = function( data, context, keepScripts ) {
9771	if ( typeof data !== "string" ) {
9772		return [];
9773	}
9774	if ( typeof context === "boolean" ) {
9775		keepScripts = context;
9776		context = false;
9777	}
9778
9779	var base, parsed, scripts;
9780
9781	if ( !context ) {
9782
9783		// Stop scripts or inline event handlers from being executed immediately
9784		// by using document.implementation
9785		if ( support.createHTMLDocument ) {
9786			context = document.implementation.createHTMLDocument( "" );
9787
9788			// Set the base href for the created document
9789			// so any parsed elements with URLs
9790			// are based on the document's URL (gh-2965)
9791			base = context.createElement( "base" );
9792			base.href = document.location.href;
9793			context.head.appendChild( base );
9794		} else {
9795			context = document;
9796		}
9797	}
9798
9799	parsed = rsingleTag.exec( data );
9800	scripts = !keepScripts && [];
9801
9802	// Single tag
9803	if ( parsed ) {
9804		return [ context.createElement( parsed[ 1 ] ) ];
9805	}
9806
9807	parsed = buildFragment( [ data ], context, scripts );
9808
9809	if ( scripts && scripts.length ) {
vendor: 4,095 bytes, lines 9810-9980
9810		jQuery( scripts ).remove();
9811	}
9812
9813	return jQuery.merge( [], parsed.childNodes );
9814};
9815
9816
9817/**
9818 * Load a url into a page
9819 */
9820jQuery.fn.load = function( url, params, callback ) {
9821	var selector, type, response,
9822		self = this,
9823		off = url.indexOf( " " );
9824
9825	if ( off > -1 ) {
9826		selector = stripAndCollapse( url.slice( off ) );
9827		url = url.slice( 0, off );
9828	}
9829
9830	// If it's a function
9831	if ( jQuery.isFunction( params ) ) {
9832
9833		// We assume that it's the callback
9834		callback = params;
9835		params = undefined;
9836
9837	// Otherwise, build a param string
9838	} else if ( params && typeof params === "object" ) {
9839		type = "POST";
9840	}
9841
9842	// If we have elements to modify, make the request
9843	if ( self.length > 0 ) {
9844		jQuery.ajax( {
9845			url: url,
9846
9847			// If "type" variable is undefined, then "GET" method will be used.
9848			// Make value of this field explicit since
9849			// user can override it through ajaxSetup method
9850			type: type || "GET",
9851			dataType: "html",
9852			data: params
9853		} ).done( function( responseText ) {
9854
9855			// Save response for use in complete callback
9856			response = arguments;
9857
9858			self.html( selector ?
9859
9860				// If a selector was specified, locate the right elements in a dummy div
9861				// Exclude scripts to avoid IE 'Permission Denied' errors
9862				jQuery( "<div>" ).append( jQuery.parseHTML( responseText ) ).find( selector ) :
9863
9864				// Otherwise use the full result
9865				responseText );
9866
9867		// If the request succeeds, this function gets "data", "status", "jqXHR"
9868		// but they are ignored because response was set above.
9869		// If it fails, this function gets "jqXHR", "status", "error"
9870		} ).always( callback && function( jqXHR, status ) {
9871			self.each( function() {
9872				callback.apply( this, response || [ jqXHR.responseText, status, jqXHR ] );
9873			} );
9874		} );
9875	}
9876
9877	return this;
9878};
9879
9880
9881
9882
9883// Attach a bunch of functions for handling common AJAX events
9884jQuery.each( [
9885	"ajaxStart",
9886	"ajaxStop",
9887	"ajaxComplete",
9888	"ajaxError",
9889	"ajaxSuccess",
9890	"ajaxSend"
9891], function( i, type ) {
9892	jQuery.fn[ type ] = function( fn ) {
9893		return this.on( type, fn );
9894	};
9895} );
9896
9897
9898
9899
9900jQuery.expr.pseudos.animated = function( elem ) {
9901	return jQuery.grep( jQuery.timers, function( fn ) {
9902		return elem === fn.elem;
9903	} ).length;
9904};
9905
9906
9907
9908
9909jQuery.offset = {
9910	setOffset: function( elem, options, i ) {
9911		var curPosition, curLeft, curCSSTop, curTop, curOffset, curCSSLeft, calculatePosition,
9912			position = jQuery.css( elem, "position" ),
9913			curElem = jQuery( elem ),
9914			props = {};
9915
9916		// Set position first, in-case top/left are set even on static elem
9917		if ( position === "static" ) {
9918			elem.style.position = "relative";
9919		}
9920
9921		curOffset = curElem.offset();
9922		curCSSTop = jQuery.css( elem, "top" );
9923		curCSSLeft = jQuery.css( elem, "left" );
9924		calculatePosition = ( position === "absolute" || position === "fixed" ) &&
9925			( curCSSTop + curCSSLeft ).indexOf( "auto" ) > -1;
9926
9927		// Need to be able to calculate position if either
9928		// top or left is auto and position is either absolute or fixed
9929		if ( calculatePosition ) {
9930			curPosition = curElem.position();
9931			curTop = curPosition.top;
9932			curLeft = curPosition.left;
9933
9934		} else {
9935			curTop = parseFloat( curCSSTop ) || 0;
9936			curLeft = parseFloat( curCSSLeft ) || 0;
9937		}
9938
9939		if ( jQuery.isFunction( options ) ) {
9940
9941			// Use jQuery.extend here to allow modification of coordinates argument (gh-1848)
9942			options = options.call( elem, i, jQuery.extend( {}, curOffset ) );
9943		}
9944
9945		if ( options.top != null ) {
9946			props.top = ( options.top - curOffset.top ) + curTop;
9947		}
9948		if ( options.left != null ) {
9949			props.left = ( options.left - curOffset.left ) + curLeft;
9950		}
9951
9952		if ( "using" in options ) {
9953			options.using.call( elem, props );
9954
9955		} else {
9956			curElem.css( props );
9957		}
9958	}
9959};
9960
9961jQuery.fn.extend( {
9962	offset: function( options ) {
9963
9964		// Preserve chaining for setter
9965		if ( arguments.length ) {
9966			return options === undefined ?
9967				this :
9968				this.each( function( i ) {
9969					jQuery.offset.setOffset( this, options, i );
9970				} );
9971		}
9972
9973		var doc, docElem, rect, win,
9974			elem = this[ 0 ];
9975
9976		if ( !elem ) {
9977			return;
9978		}
9979
9980		// Return zeros for disconnected and hidden (display: none) elements (gh-2310)
vendor: 4,119 bytes, lines 9981-10119
9981		// Support: IE <=11 only
9982		// Running getBoundingClientRect on a
9983		// disconnected node in IE throws an error
9984		if ( !elem.getClientRects().length ) {
9985			return { top: 0, left: 0 };
9986		}
9987
9988		rect = elem.getBoundingClientRect();
9989
9990		doc = elem.ownerDocument;
9991		docElem = doc.documentElement;
9992		win = doc.defaultView;
9993
9994		return {
9995			top: rect.top + win.pageYOffset - docElem.clientTop,
9996			left: rect.left + win.pageXOffset - docElem.clientLeft
9997		};
9998	},
9999
10000	position: function() {
10001		if ( !this[ 0 ] ) {
10002			return;
10003		}
10004
10005		var offsetParent, offset,
10006			elem = this[ 0 ],
10007			parentOffset = { top: 0, left: 0 };
10008
10009		// Fixed elements are offset from window (parentOffset = {top:0, left: 0},
10010		// because it is its only offset parent
10011		if ( jQuery.css( elem, "position" ) === "fixed" ) {
10012
10013			// Assume getBoundingClientRect is there when computed position is fixed
10014			offset = elem.getBoundingClientRect();
10015
10016		} else {
10017
10018			// Get *real* offsetParent
10019			offsetParent = this.offsetParent();
10020
10021			// Get correct offsets
10022			offset = this.offset();
10023			if ( !nodeName( offsetParent[ 0 ], "html" ) ) {
10024				parentOffset = offsetParent.offset();
10025			}
10026
10027			// Add offsetParent borders
10028			parentOffset = {
10029				top: parentOffset.top + jQuery.css( offsetParent[ 0 ], "borderTopWidth", true ),
10030				left: parentOffset.left + jQuery.css( offsetParent[ 0 ], "borderLeftWidth", true )
10031			};
10032		}
10033
10034		// Subtract parent offsets and element margins
10035		return {
10036			top: offset.top - parentOffset.top - jQuery.css( elem, "marginTop", true ),
10037			left: offset.left - parentOffset.left - jQuery.css( elem, "marginLeft", true )
10038		};
10039	},
10040
10041	// This method will return documentElement in the following cases:
10042	// 1) For the element inside the iframe without offsetParent, this method will return
10043	//    documentElement of the parent window
10044	// 2) For the hidden or detached element
10045	// 3) For body or html element, i.e. in case of the html node - it will return itself
10046	//
10047	// but those exceptions were never presented as a real life use-cases
10048	// and might be considered as more preferable results.
10049	//
10050	// This logic, however, is not guaranteed and can change at any point in the future
10051	offsetParent: function() {
10052		return this.map( function() {
10053			var offsetParent = this.offsetParent;
10054
10055			while ( offsetParent && jQuery.css( offsetParent, "position" ) === "static" ) {
10056				offsetParent = offsetParent.offsetParent;
10057			}
10058
10059			return offsetParent || documentElement;
10060		} );
10061	}
10062} );
10063
10064// Create scrollLeft and scrollTop methods
10065jQuery.each( { scrollLeft: "pageXOffset", scrollTop: "pageYOffset" }, function( method, prop ) {
10066	var top = "pageYOffset" === prop;
10067
10068	jQuery.fn[ method ] = function( val ) {
10069		return access( this, function( elem, method, val ) {
10070
10071			// Coalesce documents and windows
10072			var win;
10073			if ( jQuery.isWindow( elem ) ) {
10074				win = elem;
10075			} else if ( elem.nodeType === 9 ) {
10076				win = elem.defaultView;
10077			}
10078
10079			if ( val === undefined ) {
10080				return win ? win[ prop ] : elem[ method ];
10081			}
10082
10083			if ( win ) {
10084				win.scrollTo(
10085					!top ? val : win.pageXOffset,
10086					top ? val : win.pageYOffset
10087				);
10088
10089			} else {
10090				elem[ method ] = val;
10091			}
10092		}, method, val, arguments.length );
10093	};
10094} );
10095
10096// Support: Safari <=7 - 9.1, Chrome <=37 - 49
10097// Add the top/left cssHooks using jQuery.fn.position
10098// Webkit bug: https://bugs.webkit.org/show_bug.cgi?id=29084
10099// Blink bug: https://bugs.chromium.org/p/chromium/issues/detail?id=589347
10100// getComputedStyle returns percent when specified for top/left/bottom/right;
10101// rather than make the css module depend on the offset module, just check for it here
10102jQuery.each( [ "top", "left" ], function( i, prop ) {
10103	jQuery.cssHooks[ prop ] = addGetHookIf( support.pixelPosition,
10104		function( elem, computed ) {
10105			if ( computed ) {
10106				computed = curCSS( elem, prop );
10107
10108				// If curCSS returns percentage, fallback to offset
10109				return rnumnonpx.test( computed ) ?
10110					jQuery( elem ).position()[ prop ] + "px" :
10111					computed;
10112			}
10113		}
10114	);
10115} );
10116
10117
10118// Create innerHeight, innerWidth, height, width, outerHeight and outerWidth methods
10119jQuery.each( { Height: "height", Width: "width" }, function( name, type ) {
10120	jQuery.each( { padding: "inner" + name, content: type, "": "outer" + name },
10121		function( defaultExtra, funcName ) {
10122
10123		// Margin is only for outerHeight, outerWidth
10124		jQuery.fn[ funcName ] = function( margin, value ) {
10125			var chainable = arguments.length && ( defaultExtra || typeof margin !== "boolean" ),
10126				extra = defaultExtra || ( margin === true || value === true ? "margin" : "border" );
10127
10128			return access( this, function( elem, type, value ) {
10129				var doc;
10130
10131				if ( jQuery.isWindow( elem ) ) {
10132
10133					// $( window ).outerWidth/Height return w/h including scrollbars (gh-1729)
10134					return funcName.indexOf( "outer" ) === 0 ?
10135						elem[ "inner" + name ] :
10136						elem.document.documentElement[ "client" + name ];
10137				}
10138
10139				// Get document width or height
10140				if ( elem.nodeType === 9 ) {
10141					doc = elem.documentElement;
10142
10143					// Either scroll[Width/Height] or offset[Width/Height] or client[Width/Height],
10144					// whichever is greatest
10145					return Math.max(
10146						elem.body[ "scroll" + name ], doc[ "scroll" + name ],
10147						elem.body[ "offset" + name ], doc[ "offset" + name ],
10148						doc[ "client" + name ]
10149					);
10150				}
10151
10152				return value === undefined ?
10153
10154					// Get width or height on the element, requesting but not forcing parseFloat
10155					jQuery.css( elem, type, extra ) :
10156
10157					// Set width or height on the element
10158					jQuery.style( elem, type, value, extra );
10159			}, type, chainable ? margin : undefined, chainable );
10160		};
10161	} );
10162} );
10163
10164
10165jQuery.fn.extend( {
10166
10167	bind: function( types, data, fn ) {
10168		return this.on( types, null, data, fn );
10169	},
10170	unbind: function( types, fn ) {
10171		return this.off( types, null, fn );
10172	},
10173
10174	delegate: function( selector, types, data, fn ) {
10175		return this.on( types, selector, data, fn );
10176	},
10177	undelegate: function( selector, types, fn ) {
10178
10179		// ( namespace ) or ( selector, types [, fn] )
10180		return arguments.length === 1 ?
10181			this.off( selector, "**" ) :
10182			this.off( types, selector || "**", fn );
10183	}
10184} );
10185
10186jQuery.holdReady = function( hold ) {
10187	if ( hold ) {
10188		jQuery.readyWait++;
10189	} else {
10190		jQuery.ready( true );
10191	}
10192};
10193jQuery.isArray = Array.isArray;
10194jQuery.parseJSON = JSON.parse;
10195jQuery.nodeName = nodeName;
10196
10197
10198
10199
10200// Register as a named AMD module, since jQuery can be concatenated with other
10201// files that may use define, but not via a proper concatenation script that
10202// understands anonymous AMD modules. A named AMD is safest and most robust
10203// way to register. Lowercase jquery is used because AMD module names are
10204// derived from file names, and jQuery is normally delivered in a lowercase
10205// file name. Do this after creating the global so that if an AMD module wants
10206// to call noConflict to hide this version of jQuery, it will work.
10207
10208// Note that for maximum portability, libraries that are not jQuery should
10209// declare themselves as anonymous modules, and avoid setting a global if an
10210// AMD loader is present. jQuery is a special case. For more information, see
10211// https://github.com/jrburke/requirejs/wiki/Updating-existing-libraries#wiki-anon
10212
10213if ( typeof define === "function" && define.amd ) {
10214	define( "jquery", [], function() {
10215		return jQuery;
10216	} );
10217}
10218
10219
10220
10221
10222var
10223
10224	// Map over jQuery in case of overwrite
10225	_jQuery = window.jQuery,
10226
10227	// Map over the $ in case of overwrite
10228	_$ = window.$;
10229
10230jQuery.noConflict = function( deep ) {
10231	if ( window.$ === jQuery ) {
10232		window.$ = _$;
10233	}
10234
10235	if ( deep && window.jQuery === jQuery ) {
10236		window.jQuery = _jQuery;
10237	}
10238
10239	return jQuery;
10240};
10241
10242// Expose jQuery and $ identifiers, even in AMD
10243// (#7102#comment:10, https://github.com/jquery/jquery/pull/557)
10244// and CommonJS for browser emulators (#13566)
10245if ( !noGlobal ) {
10246	window.jQuery = window.$ = jQuery;
10247}
10248
10249
10250
10251
10252return jQuery;
10253} );
10254
10255/**
10256 * @license AngularJS v1.6.3
10257 * (c) 2010-2017 Google, Inc. http://angularjs.org
10258 * License: MIT
10259 */
10260(function(window) {'use strict';
10261
10262/**
10263 * @description
10264 *
10265 * This object provides a utility for producing rich Error messages within
10266 * Angular. It can be called as follows:
10267 *
10268 * var exampleMinErr = minErr('example');
10269 * throw exampleMinErr('one', 'This {0} is {1}', foo, bar);
10270 *
10271 * The above creates an instance of minErr in the example namespace. The
10272 * resulting error will have a namespaced error code of example.one.  The
10273 * resulting error will replace {0} with the value of foo, and {1} with the
10274 * value of bar. The object is not restricted in the number of arguments it can
10275 * take.
10276 *
10277 * If fewer arguments are specified than necessary for interpolation, the extra
10278 * interpolation markers will be preserved in the final string.
10279 *
10280 * Since data will be parsed statically during a build step, some restrictions
10281 * are applied with respect to how minErr instances are created and called.
10282 * Instances should have names of the form namespaceMinErr for a minErr created
10283 * using minErr('namespace') . Error codes, namespaces and template strings
10284 * should all be static strings, not variables or general expressions.
10285 *
10286 * @param {string} module The namespace to use for the new minErr instance.
10287 * @param {function} ErrorConstructor Custom error constructor to be instantiated when returning
10288 *   error from returned function, for cases when a particular type of error is useful.
10289 * @returns {function(code:string, template:string, ...templateArgs): Error} minErr instance
10290 */
10291
10292function minErr(module, ErrorConstructor) {
10293  ErrorConstructor = ErrorConstructor || Error;
10294  return function() {
10295    var code = arguments[0],
10296      template = arguments[1],
10297      message = '[' + (module ? module + ':' : '') + code + '] ',
10298      templateArgs = sliceArgs(arguments, 2).map(function(arg) {
10299        return toDebugString(arg, minErrConfig.objectMaxDepth);
10300      }),
10301      paramPrefix, i;
10302
10303    message += template.replace(/\{\d+\}/g, function(match) {
10304      var index = +match.slice(1, -1);
10305
10306      if (index < templateArgs.length) {
10307        return templateArgs[index];
10308      }
10309
10310      return match;
10311    });
10312
10313    message += '\nhttp://errors.angularjs.org/1.6.3/' +
10314      (module ? module + '/' : '') + code;
10315
10316    for (i = 0, paramPrefix = '?'; i < templateArgs.length; i++, paramPrefix = '&') {
10317      message += paramPrefix + 'p' + i + '=' + encodeURIComponent(templateArgs[i]);
10318    }
10319
10320    return new ErrorConstructor(message);
10321  };
10322}
10323
10324/* We need to tell ESLint what variables are being exported */
10325/* exported
10326  angular,
10327  msie,
10328  jqLite,
10329  jQuery,
10330  slice,
10331  splice,
10332  push,
10333  toString,
10334  minErrConfig,
10335  errorHandlingConfig,
10336  isValidObjectMaxDepth,
10337  ngMinErr,
10338  angularModule,
10339  uid,
10340  REGEX_STRING_REGEXP,
10341  VALIDITY_STATE_PROPERTY,
10342
10343  lowercase,
10344  uppercase,
10345  manualLowercase,
10346  manualUppercase,
10347  nodeName_,
10348  isArrayLike,
10349  forEach,
10350  forEachSorted,
10351  reverseParams,
10352  nextUid,
10353  setHashKey,
10354  extend,
10355  toInt,
10356  inherit,
10357  merge,
10358  noop,
10359  identity,
10360  valueFn,
10361  isUndefined,
10362  isDefined,
10363  isObject,
10364  isBlankObject,
10365  isString,
10366  isNumber,
10367  isNumberNaN,
10368  isDate,
10369  isArray,
10370  isFunction,
10371  isRegExp,
10372  isWindow,
10373  isScope,
10374  isFile,
10375  isFormData,
10376  isBlob,
10377  isBoolean,
10378  isPromiseLike,
10379  trim,
10380  escapeForRegexp,
10381  isElement,
10382  makeMap,
10383  includes,
10384  arrayRemove,
10385  copy,
10386  equals,
10387  csp,
10388  jq,
10389  concat,
10390  sliceArgs,
10391  bind,
10392  toJsonReplacer,
10393  toJson,
10394  fromJson,
10395  convertTimezoneToLocal,
10396  timezoneToOffset,
10397  startingTag,
10398  tryDecodeURIComponent,
10399  parseKeyValue,
10400  toKeyValue,
10401  encodeUriSegment,
10402  encodeUriQuery,
10403  angularInit,
10404  bootstrap,
10405  getTestability,
10406  snake_case,
10407  bindJQuery,
10408  assertArg,
10409  assertArgFn,
10410  assertNotHasOwnProperty,
10411  getter,
10412  getBlockNodes,
10413  hasOwnProperty,
10414  createMap,
10415  stringify,
10416
10417  NODE_TYPE_ELEMENT,
10418  NODE_TYPE_ATTRIBUTE,
10419  NODE_TYPE_TEXT,
10420  NODE_TYPE_COMMENT,
10421  NODE_TYPE_DOCUMENT,
10422  NODE_TYPE_DOCUMENT_FRAGMENT
10423*/
10424
10425////////////////////////////////////
10426
10427/**
10428 * @ngdoc module
10429 * @name ng
10430 * @module ng
10431 * @installation
10432 * @description
10433 *
10434 * # ng (core module)
10435 * The ng module is loaded by default when an AngularJS application is started. The module itself
10436 * contains the essential components for an AngularJS application to function. The table below
10437 * lists a high level breakdown of each of the services/factories, filters, directives and testing
10438 * components available within this core module.
10439 *
10440 * <div doc-module-components="ng"></div>
10441 */
10442
10443var REGEX_STRING_REGEXP = /^\/(.+)\/([a-z]*)$/;
10444
10445// The name of a form control's ValidityState property.
10446// This is used so that it's possible for internal tests to create mock ValidityStates.
10447var VALIDITY_STATE_PROPERTY = 'validity';
10448
10449
10450var hasOwnProperty = Object.prototype.hasOwnProperty;
10451
10452var minErrConfig = {
10453  objectMaxDepth: 5
10454};
10455
10456 /**
10457 * @ngdoc function
10458 * @name angular.errorHandlingConfig
10459 * @module ng
10460 * @kind function
10461 *
10462 * @description
10463 * Configure several aspects of error handling in AngularJS if used as a setter or return the
10464 * current configuration if used as a getter. The following options are supported:
10465 *
10466 * - **objectMaxDepth**: The maximum depth to which objects are traversed when stringified for error messages.
10467 *
10468 * Omitted or undefined options will leave the corresponding configuration values unchanged.
10469 *
10470 * @param {Object=} config - The configuration object. May only contain the options that need to be
10471 *     updated. Supported keys:
10472 *
10473 * * `objectMaxDepth`  **{Number}** - The max depth for stringifying objects. Setting to a
10474 *   non-positive or non-numeric value, removes the max depth limit.
10475 *   Default: 5
10476 */
10477function errorHandlingConfig(config) {
10478  if (isObject(config)) {
10479    if (isDefined(config.objectMaxDepth)) {
10480      minErrConfig.objectMaxDepth = isValidObjectMaxDepth(config.objectMaxDepth) ? config.objectMaxDepth : NaN;
10481    }
10482  } else {
10483    return minErrConfig;
10484  }
10485}
10486
10487/**
10488 * @private
10489 * @param {Number} maxDepth
10490 * @return {boolean}
10491 */
10492function isValidObjectMaxDepth(maxDepth) {
10493  return isNumber(maxDepth) && maxDepth > 0;
10494}
10495
10496/**
10497 * @ngdoc function
10498 * @name angular.lowercase
10499 * @module ng
10500 * @kind function
10501 *
10502 * @deprecated
10503 * sinceVersion="1.5.0"
10504 * removeVersion="1.7.0"
10505 * Use [String.prototype.toLowerCase](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String/toLowerCase) instead.
10506 *
10507 * @description Converts the specified string to lowercase.
10508 * @param {string} string String to be converted to lowercase.
10509 * @returns {string} Lowercased string.
10510 */
10511var lowercase = function(string) {return isString(string) ? string.toLowerCase() : string;};
10512
10513/**
10514 * @ngdoc function
10515 * @name angular.uppercase
10516 * @module ng
10517 * @kind function
10518 *
10519 * @deprecated
10520 * sinceVersion="1.5.0"
10521 * removeVersion="1.7.0"
10522 * Use [String.prototype.toUpperCase](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String/toUpperCase) instead.
10523 *
10524 * @description Converts the specified string to uppercase.
10525 * @param {string} string String to be converted to uppercase.
10526 * @returns {string} Uppercased string.
10527 */
10528var uppercase = function(string) {return isString(string) ? string.toUpperCase() : string;};
10529
10530
10531var manualLowercase = function(s) {
10532  /* eslint-disable no-bitwise */
10533  return isString(s)
10534      ? s.replace(/[A-Z]/g, function(ch) {return String.fromCharCode(ch.charCo
10534deAt(0) | 32);})
10535      : s;
10536  /* eslint-enable */
10537};
10538var manualUppercase = function(s) {
10539  /* eslint-disable no-bitwise */
10540  return isString(s)
10541      ? s.replace(/[a-z]/g, function(ch) {return String.fromCharCode(ch.charCodeAt(0) & ~32);})
10542      : s;
10543  /* eslint-enable */
10544};
10545
10546
10547// String#toLowerCase and String#toUpperCase don't produce correct results in browsers with Turkish
10548// locale, for this reason we need to detect this case and redefine lowercase/uppercase methods
10549// with correct but slower alternatives. See https://github.com/angular/angular.js/issues/11387
10550if ('i' !== 'I'.toLowerCase()) {
10551  lowercase = manualLowercase;
10552  uppercase = manualUppercase;
10553}
10554
10555
10556var
10557    msie,             // holds major version number for IE, or NaN if UA is not IE.
10558    jqLite,           // delay binding since jQuery could be loaded after us.
10559    jQuery,           // delay binding
10560    slice             = [].slice,
10561    splice            = [].splice,
10562    push              = [].push,
10563    toString          = Object.prototype.toString,
10564    getPrototypeOf    = Object.getPrototypeOf,
10565    ngMinErr          = minErr('ng'),
10566
10567    /** @name angular */
10568    angular           = window.angular || (window.angular = {}),
10569    angularModule,
10570    uid               = 0;
10571
10572// Support: IE 9-11 only
10573/**
10574 * documentMode is an IE-only property
10575 * http://msdn.microsoft.com/en-us/library/ie/cc196988(v=vs.85).aspx
10576 */
10577msie = window.document.documentMode;
10578
10579
10580/**
10581 * @private
10582 * @param {*} obj
10583 * @return {boolean} Returns true if `obj` is an array or array-like object (NodeList, Arguments,
10584 *                   String ...)
10585 */
10586function isArrayLike(obj) {
10587
10588  // `null`, `undefined` and `window` are not array-like
10589  if (obj == null || isWindow(obj)) return false;
10590
10591  // arrays, strings and jQuery/jqLite objects are array like
10592  // * jqLite is either the jQuery or jqLite constructor function
10593  // * we have to check the existence of jqLite first as this method is called
10594  //   via the forEach method when constructing the jqLite object in the first place
10595  if (isArray(obj) || isString(obj) || (jqLite && obj instanceof jqLite)) return true;
10596
10597  // Support: iOS 8.2 (not reproducible in simulator)
10598  // "length" in obj used to prevent JIT error (gh-11508)
10599  var length = 'length' in Object(obj) && obj.length;
10600
10601  // NodeList objects (with `item` method) and
10602  // other objects with suitable length characteristics are array-like
10603  return isNumber(length) &&
10604    (length >= 0 && ((length - 1) in obj || obj instanceof Array) || typeof obj.item === 'function');
10605
10606}
10607
10608/**
10609 * @ngdoc function
10610 * @name angular.forEach
10611 * @module ng
10612 * @kind function
10613 *
10614 * @description
10615 * Invokes the `iterator` function once for each item in `obj` collection, which can be either an
10616 * object or an array. The `iterator` function is invoked with `iterator(value, key, obj)`, where `value`
10617 * is the value of an object property or an array element, `key` is the object property key or
10618 * array element index and obj is the `obj` itself. Specifying a `context` for the function is optional.
10619 *
10620 * It is worth noting that `.forEach` does not iterate over inherited properties because it filters
10621 * using the `hasOwnProperty` method.
10622 *
10623 * Unlike ES262's
10624 * [Array.prototype.forEach](http://www.ecma-international.org/ecma-262/5.1/#sec-15.4.4.18),
10625 * providing 'undefined' or 'null' values for `obj` will not throw a TypeError, but rather just
10626 * return the value provided.
10627 *
10628   ```js
10629     var values = {name: 'misko', gender: 'male'};
10630     var log = [];
10631     angular.forEach(values, function(value, key) {
10632       this.push(key + ': ' + value);
10633     }, log);
10634     expect(log).toEqual(['name: misko', 'gender: male']);
10635   ```
10636 *
10637 * @param {Object|Array} obj Object to iterate over.
10638 * @param {Function} iterator Iterator function.
10639 * @param {Object=} context Object to become context (`this`) for the iterator function.
10640 * @returns {Object|Array} Reference to `obj`.
10641 */
10642
10643function forEach(obj, iterator, context) {
10644  var key, length;
10645  if (obj) {
10646    if (isFunction(obj)) {
10647      for (key in obj) {
10648        if (key !== 'prototype' && key !== 'length' && key !== 'name' && obj.hasOwnProperty(key)) {
10649          iterator.call(context, obj[key], key, obj);
10650        }
10651      }
10652    } else if (isArray(obj) || isArrayLike(obj)) {
10653      var isPrimitive = typeof obj !== 'object';
10654      for (key = 0, length = obj.length; key < length; key++) {
10655        if (isPrimitive || key in obj) {
10656          iterator.call(context, obj[key], key, obj);
10657        }
10658      }
10659    }
vendor: 12,114 bytes, lines 10659-11160
10659 else if (obj.forEach && obj.forEach !== forEach) {
10660        obj.forEach(iterator, context, obj);
10661    } else if (isBlankObject(obj)) {
10662      // createMap() fast path --- Safe to avoid hasOwnProperty check because prototype chain is empty
10663      for (key in obj) {
10664        iterator.call(context, obj[key], key, obj);
10665      }
10666    } else if (typeof obj.hasOwnProperty === 'function') {
10667      // Slow path for objects inheriting Object.prototype, hasOwnProperty check needed
10668      for (key in obj) {
10669        if (obj.hasOwnProperty(key)) {
10670          iterator.call(context, obj[key], key, obj);
10671        }
10672      }
10673    } else {
10674      // Slow path for objects which do not have a method `hasOwnProperty`
10675      for (key in obj) {
10676        if (hasOwnProperty.call(obj, key)) {
10677          iterator.call(context, obj[key], key, obj);
10678        }
10679      }
10680    }
10681  }
10682  return obj;
10683}
10684
10685function forEachSorted(obj, iterator, context) {
10686  var keys = Object.keys(obj).sort();
10687  for (var i = 0; i < keys.length; i++) {
10688    iterator.call(context, obj[keys[i]], keys[i]);
10689  }
10690  return keys;
10691}
10692
10693
10694/**
10695 * when using forEach the params are value, key, but it is often useful to have key, value.
10696 * @param {function(string, *)} iteratorFn
10697 * @returns {function(*, string)}
10698 */
10699function reverseParams(iteratorFn) {
10700  return function(value, key) {iteratorFn(key, value);};
10701}
10702
10703/**
10704 * A consistent way of creating unique IDs in angular.
10705 *
10706 * Using simple numbers allows us to generate 28.6 million unique ids per second for 10 years before
10707 * we hit number precision issues in JavaScript.
10708 *
10709 * Math.pow(2,53) / 60 / 60 / 24 / 365 / 10 = 28.6M
10710 *
10711 * @returns {number} an unique alpha-numeric string
10712 */
10713function nextUid() {
10714  return ++uid;
10715}
10716
10717
10718/**
10719 * Set or clear the hashkey for an object.
10720 * @param obj object
10721 * @param h the hashkey (!truthy to delete the hashkey)
10722 */
10723function setHashKey(obj, h) {
10724  if (h) {
10725    obj.$$hashKey = h;
10726  } else {
10727    delete obj.$$hashKey;
10728  }
10729}
10730
10731
10732function baseExtend(dst, objs, deep) {
10733  var h = dst.$$hashKey;
10734
10735  for (var i = 0, ii = objs.length; i < ii; ++i) {
10736    var obj = objs[i];
10737    if (!isObject(obj) && !isFunction(obj)) continue;
10738    var keys = Object.keys(obj);
10739    for (var j = 0, jj = keys.length; j < jj; j++) {
10740      var key = keys[j];
10741      var src = obj[key];
10742
10743      if (deep && isObject(src)) {
10744        if (isDate(src)) {
10745          dst[key] = new Date(src.valueOf());
10746        } else if (isRegExp(src)) {
10747          dst[key] = new RegExp(src);
10748        } else if (src.nodeName) {
10749          dst[key] = src.cloneNode(true);
10750        } else if (isElement(src)) {
10751          dst[key] = src.clone();
10752        } else {
10753          if (!isObject(dst[key])) dst[key] = isArray(src) ? [] : {};
10754          baseExtend(dst[key], [src], true);
10755        }
10756      } else {
10757        dst[key] = src;
10758      }
10759    }
10760  }
10761
10762  setHashKey(dst, h);
10763  return dst;
10764}
10765
10766/**
10767 * @ngdoc function
10768 * @name angular.extend
10769 * @module ng
10770 * @kind function
10771 *
10772 * @description
10773 * Extends the destination object `dst` by copying own enumerable properties from the `src` object(s)
10774 * to `dst`. You can specify multiple `src` objects. If you want to preserve original objects, you can do so
10775 * by passing an empty object as the target: `var object = angular.extend({}, object1, object2)`.
10776 *
10777 * **Note:** Keep in mind that `angular.extend` does not support recursive merge (deep copy). Use
10778 * {@link angular.merge} for this.
10779 *
10780 * @param {Object} dst Destination object.
10781 * @param {...Object} src Source object(s).
10782 * @returns {Object} Reference to `dst`.
10783 */
10784function extend(dst) {
10785  return baseExtend(dst, slice.call(arguments, 1), false);
10786}
10787
10788
10789/**
10790* @ngdoc function
10791* @name angular.merge
10792* @module ng
10793* @kind function
10794*
10795* @description
10796* Deeply extends the destination object `dst` by copying own enumerable properties from the `src` object(s)
10797* to `dst`. You can specify multiple `src` objects. If you want to preserve original objects, you can do so
10798* by passing an empty object as the target: `var object = angular.merge({}, object1, object2)`.
10799*
10800* Unlike {@link angular.extend extend()}, `merge()` recursively descends into object properties of source
10801* objects, performing a deep copy.
10802*
10803* @param {Object} dst Destination object.
10804* @param {...Object} src Source object(s).
10805* @returns {Object} Reference to `dst`.
10806*/
10807function merge(dst) {
10808  return baseExtend(dst, slice.call(arguments, 1), true);
10809}
10810
10811
10812
10813function toInt(str) {
10814  return parseInt(str, 10);
10815}
10816
10817var isNumberNaN = Number.isNaN || function isNumberNaN(num) {
10818  // eslint-disable-next-line no-self-compare
10819  return num !== num;
10820};
10821
10822
10823function inherit(parent, extra) {
10824  return extend(Object.create(parent), extra);
10825}
10826
10827/**
10828 * @ngdoc function
10829 * @name angular.noop
10830 * @module ng
10831 * @kind function
10832 *
10833 * @description
10834 * A function that performs no operations. This function can be useful when writing code in the
10835 * functional style.
10836   ```js
10837     function foo(callback) {
10838       var result = calculateResult();
10839       (callback || angular.noop)(result);
10840     }
10841   ```
10842 */
10843function noop() {}
10844noop.$inject = [];
10845
10846
10847/**
10848 * @ngdoc function
10849 * @name angular.identity
10850 * @module ng
10851 * @kind function
10852 *
10853 * @description
10854 * A function that returns its first argument. This function is useful when writing code in the
10855 * functional style.
10856 *
10857   ```js
10858   function transformer(transformationFn, value) {
10859     return (transformationFn || angular.identity)(value);
10860   };
10861
10862   // E.g.
10863   function getResult(fn, input) {
10864     return (fn || angular.identity)(input);
10865   };
10866
10867   getResult(function(n) { return n * 2; }, 21);   // returns 42
10868   getResult(null, 21);                            // returns 21
10869   getResult(undefined, 21);                       // returns 21
10870   ```
10871 *
10872 * @param {*} value to be returned.
10873 * @returns {*} the value passed in.
10874 */
10875function identity($) {return $;}
10876identity.$inject = [];
10877
10878
10879function valueFn(value) {return function valueRef() {return value;};}
10880
10881function hasCustomToString(obj) {
10882  return isFunction(obj.toString) && obj.toString !== toString;
10883}
10884
10885
10886/**
10887 * @ngdoc function
10888 * @name angular.isUndefined
10889 * @module ng
10890 * @kind function
10891 *
10892 * @description
10893 * Determines if a reference is undefined.
10894 *
10895 * @param {*} value Reference to check.
10896 * @returns {boolean} True if `value` is undefined.
10897 */
10898function isUndefined(value) {return typeof value === 'undefined';}
10899
10900
10901/**
10902 * @ngdoc function
10903 * @name angular.isDefined
10904 * @module ng
10905 * @kind function
10906 *
10907 * @description
10908 * Determines if a reference is defined.
10909 *
10910 * @param {*} value Reference to check.
10911 * @returns {boolean} True if `value` is defined.
10912 */
10913function isDefined(value) {return typeof value !== 'undefined';}
10914
10915
10916/**
10917 * @ngdoc function
10918 * @name angular.isObject
10919 * @module ng
10920 * @kind function
10921 *
10922 * @description
10923 * Determines if a reference is an `Object`. Unlike `typeof` in JavaScript, `null`s are not
10924 * considered to be objects. Note that JavaScript arrays are objects.
10925 *
10926 * @param {*} value Reference to check.
10927 * @returns {boolean} True if `value` is an `Object` but not `null`.
10928 */
10929function isObject(value) {
10930  // http://jsperf.com/isobject4
10931  return value !== null && typeof value === 'object';
10932}
10933
10934
10935/**
10936 * Determine if a value is an object with a null prototype
10937 *
10938 * @returns {boolean} True if `value` is an `Object` with a null prototype
10939 */
10940function isBlankObject(value) {
10941  return value !== null && typeof value === 'object' && !getPrototypeOf(value);
10942}
10943
10944
10945/**
10946 * @ngdoc function
10947 * @name angular.isString
10948 * @module ng
10949 * @kind function
10950 *
10951 * @description
10952 * Determines if a reference is a `String`.
10953 *
10954 * @param {*} value Reference to check.
10955 * @returns {boolean} True if `value` is a `String`.
10956 */
10957function isString(value) {return typeof value === 'string';}
10958
10959
10960/**
10961 * @ngdoc function
10962 * @name angular.isNumber
10963 * @module ng
10964 * @kind function
10965 *
10966 * @description
10967 * Determines if a reference is a `Number`.
10968 *
10969 * This includes the "special" numbers `NaN`, `+Infinity` and `-Infinity`.
10970 *
10971 * If you wish to exclude these then you can use the native
10972 * [`isFinite'](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/isFinite)
10973 * method.
10974 *
10975 * @param {*} value Reference to check.
10976 * @returns {boolean} True if `value` is a `Number`.
10977 */
10978function isNumber(value) {return typeof value === 'number';}
10979
10980
10981/**
10982 * @ngdoc function
10983 * @name angular.isDate
10984 * @module ng
10985 * @kind function
10986 *
10987 * @description
10988 * Determines if a value is a date.
10989 *
10990 * @param {*} value Reference to check.
10991 * @returns {boolean} True if `value` is a `Date`.
10992 */
10993function isDate(value) {
10994  return toString.call(value) === '[object Date]';
10995}
10996
10997
10998/**
10999 * @ngdoc function
11000 * @name angular.isArray
11001 * @module ng
11002 * @kind function
11003 *
11004 * @description
11005 * Determines if a reference is an `Array`. Alias of Array.isArray.
11006 *
11007 * @param {*} value Reference to check.
11008 * @returns {boolean} True if `value` is an `Array`.
11009 */
11010var isArray = Array.isArray;
11011
11012/**
11013 * @ngdoc function
11014 * @name angular.isFunction
11015 * @module ng
11016 * @kind function
11017 *
11018 * @description
11019 * Determines if a reference is a `Function`.
11020 *
11021 * @param {*} value Reference to check.
11022 * @returns {boolean} True if `value` is a `Function`.
11023 */
11024function isFunction(value) {return typeof value === 'function';}
11025
11026
11027/**
11028 * Determines if a value is a regular expression object.
11029 *
11030 * @private
11031 * @param {*} value Reference to check.
11032 * @returns {boolean} True if `value` is a `RegExp`.
11033 */
11034function isRegExp(value) {
11035  return toString.call(value) === '[object RegExp]';
11036}
11037
11038
11039/**
11040 * Checks if `obj` is a window object.
11041 *
11042 * @private
11043 * @param {*} obj Object to check
11044 * @returns {boolean} True if `obj` is a window obj.
11045 */
11046function isWindow(obj) {
11047  return obj && obj.window === obj;
11048}
11049
11050
11051function isScope(obj) {
11052  return obj && obj.$evalAsync && obj.$watch;
11053}
11054
11055
11056function isFile(obj) {
11057  return toString.call(obj) === '[object File]';
11058}
11059
11060
11061function isFormData(obj) {
11062  return toString.call(obj) === '[object FormData]';
11063}
11064
11065
11066function isBlob(obj) {
11067  return toString.call(obj) === '[object Blob]';
11068}
11069
11070
11071function isBoolean(value) {
11072  return typeof value === 'boolean';
11073}
11074
11075
11076function isPromiseLike(obj) {
11077  return obj && isFunction(obj.then);
11078}
11079
11080
11081var TYPED_ARRAY_REGEXP = /^\[object (?:Uint8|Uint8Clamped|Uint16|Uint32|Int8|Int16|Int32|Float32|Float64)Array]$/;
11082function isTypedArray(value) {
11083  return value && isNumber(value.length) && TYPED_ARRAY_REGEXP.test(toString.call(value));
11084}
11085
11086function isArrayBuffer(obj) {
11087  return toString.call(obj) === '[object ArrayBuffer]';
11088}
11089
11090
11091var trim = function(value) {
11092  return isString(value) ? value.trim() : value;
11093};
11094
11095// Copied from:
11096// http://docs.closure-library.googlecode.com/git/local_closure_goog_string_string.js.source.html#line1021
11097// Prereq: s is a string.
11098var escapeForRegexp = function(s) {
11099  return s
11100    .replace(/([-()[\]{}+?*.$^|,:#<!\\])/g, '\\$1')
11101    // eslint-disable-next-line no-control-regex
11102    .replace(/\x08/g, '\\x08');
11103};
11104
11105
11106/**
11107 * @ngdoc function
11108 * @name angular.isElement
11109 * @module ng
11110 * @kind function
11111 *
11112 * @description
11113 * Determines if a reference is a DOM element (or wrapped jQuery element).
11114 *
11115 * @param {*} value Reference to check.
11116 * @returns {boolean} True if `value` is a DOM element (or wrapped jQuery element).
11117 */
11118function isElement(node) {
11119  return !!(node &&
11120    (node.nodeName  // We are a direct element.
11121    || (node.prop && node.attr && node.find)));  // We have an on and find method part of jQuery API.
11122}
11123
11124/**
11125 * @param str 'key1,key2,...'
11126 * @returns {object} in the form of {key1:true, key2:true, ...}
11127 */
11128function makeMap(str) {
11129  var obj = {}, items = str.split(','), i;
11130  for (i = 0; i < items.length; i++) {
11131    obj[items[i]] = true;
11132  }
11133  return obj;
11134}
11135
11136
11137function nodeName_(element) {
11138  return lowercase(element.nodeName || (element[0] && element[0].nodeName));
11139}
11140
11141function includes(array, obj) {
11142  return Array.prototype.indexOf.call(array, obj) !== -1;
11143}
11144
11145function arrayRemove(array, value) {
11146  var index = array.indexOf(value);
11147  if (index >= 0) {
11148    array.splice(index, 1);
11149  }
11150  return index;
11151}
11152
11153/**
11154 * @ngdoc function
11155 * @name angular.copy
11156 * @module ng
11157 * @kind function
11158 *
11159 * @description
11160 * Creates a deep copy of `source`, which should be an object or an array.
11161 *
11162 * * If no destination is supplied, a copy of the object or array is created.
11163 * * If a destination is provided, all of its elements (for arrays) or properties (for objects)
11164 *   are deleted and then all elements/properties from the source are copied to it.
11165 * * If `source` is not an object or array (inc. `null` and `undefined`), `source` is returned.
11166 * * If `source` is identical to `destination` an exception will be thrown.
11167 *
11168 * <br />
11169 * <div class="alert alert-warning">
11170 *   Only enumerable properties are taken into account. Non-enumerable properties (both on `source`
11171 *   and on `destination`) will be ignored.
11172 * </div>
11173 *
11174 * @param {*} source The source that will be used to make a copy.
11175 *                   Can be any type, including primitives, `null`, and `undefined`.
11176 * @param {(Object|Array)=} destination Destination into which the source is copied. If
11177 *     provided, must be of the same type as `source`.
11178 * @returns {*} The copy or updated `destination`, if `destination` was specified.
11179 *
11180 * @example
11181  <example module="copyExample" name="angular-copy">
11182    <file name="index.html">
11183      <div ng-controller="ExampleController">
11184        <form novalidate class="simple-form">
11185          <label>Name: <input type="text" ng-model="user.name" /></label><br />
11186          <label>Age:  <input type="number" ng-model="user.age" /></label><br />
11187          Gender: <label><input type="radio" ng-model="user.gender" value="male" />male</label>
11188                  <label><input type="radio" ng-model="user.gender" value="female" />female</label><br />
11189          <button ng-click="reset()">RESET</button>
11190          <button ng-click="update(user)">SAVE</button>
11191        </form>
11192        <pre>form = {{user | json}}</pre>
11193        <pre>master = {{master | json}}</pre>
11194      </div>
11195    </file>
11196    <file name="script.js">
11197      // Module: copyExample
11198      angular.
11199        module('copyExample', []).
11200        controller('ExampleController', ['$scope', function($scope) {
11201          $scope.master = {};
11202
11203          $scope.reset = function() {
11204            // Example with 1 argument
11205            $scope.user = angular.copy($scope.master);
11206          };
11207
11208          $scope.update = function(user) {
11209            // Example with 2 arguments
11210            angular.copy(user, $scope.master);
11211          };
11212
11213          $scope.reset();
11214        }]);
11215    </file>
11216  </example>
11217 */
11218function copy(source, destination, maxDepth) {
11219  var stackSource = [];
11220  var stackDest = [];
11221  maxDepth = isValidObjectMaxDepth(maxDepth) ? maxDepth : NaN;
11222
11223  if (destination) {
11224    if (isTypedArray(destination) || isArrayBuffer(destination)) {
11225      throw ngMinErr('cpta', 'Can\'t copy! TypedArray destination cannot be mutated.');
11226    }
11227    if (source === destination) {
11228      throw ngMinErr('cpi', 'Can\'t copy! Source and destination are identical.');
11229    }
11230
11231    // Empty the destination object
11232    if (isArray(destination)) {
11233      destination.length = 0;
11234    } else {
11235      forEach(destination, function(value, key) {
11236        if (key !== '$$hashKey') {
11237          delete destination[key];
11238        }
11239      });
11240    }
11241
11242    stackSource.push(source);
11243    stackDest.push(destination);
11244    return copyRecurse(source, destination, maxDepth);
11245  }
11246
11247  return copyElement(source, maxDepth);
11248
11249  function copyRecurse(source, destination, maxDepth) {
11250    maxDepth--;
11251    if (maxDepth < 0) {
11252      return '...';
11253    }
11254    var h = destination.$$hashKey;
11255    var key;
11256    if (isArray(source)) {
11257      for (var i = 0, ii = source.length; i < ii; i++) {
11258        destination.push(copyElement(source[i], maxDepth));
11259      }
11260    } else if (isBlankObject(source)) {
11261      // createMap() fast path --- Safe to avoid hasOwnProperty check because prototype chain is empty
11262      for (key in source) {
11263        destination[key] = copyElement(source[key], maxDepth);
11264      }
11265    } else if (source && typeof source.hasOwnProperty === 'function') {
11266      // Slow path, which must rely on hasOwnProperty
11267      for (key in source) {
11268        if (source.hasOwnProperty(key)) {
11269          destination[key] = copyElement(source[key], maxDepth);
11270        }
11271      }
11272    } else {
11273      // Slowest path --- hasOwnProperty can't be called as a method
11274      for (key in source) {
11275        if (hasOwnProperty.call(source, key)) {
11276          destination[key] = copyElement(source[key], maxDepth);
11277        }
11278      }
11279    }
11280    setHashKey(destination, h);
11281    return destination;
11282  }
11283
11284  function copyElement(source, maxDepth) {
11285    // Simple values
11286    if (!isObject(source)) {
11287      return source;
11288    }
11289
11290    // Already copied values
11291    var index = stackSource.indexOf(source);
11292    if (index !== -1) {
11293      return stackDest[index];
11294    }
11295
11296    if (isWindow(source) || isScope(source)) {
11297      throw ngMinErr('cpws',
11298        'Can\'t copy! Making copies of Window or Scope instances is not supported.');
11299    }
11300
11301    var needsRecurse = false;
11302    var destination = copyType(source);
11303
11304    if (destination === undefined) {
11305      destination = isArray(source) ? [] : Object.create(getPrototypeOf(source));
11306      needsRecurse = true;
11307    }
11308
11309    stackSource.push(source);
11310    stackDest.push(destination);
11311
11312    return needsRecurse
11313      ? copyRecurse(source, destination, maxDepth)
11314      : destination;
11315  }
11316
11317  function copyType(source) {
11318    switch (toString.call(source)) {
11319      case '[object Int8Array]':
11320      case '[object Int16Array]':
11321      case '[object Int32Array]':
11322      case '[object Float32Array]':
vendor: 18,304 bytes, lines 11323-11915
11323      case '[object Float64Array]':
11324      case '[object Uint8Array]':
11325      case '[object Uint8ClampedArray]':
11326      case '[object Uint16Array]':
11327      case '[object Uint32Array]':
11328        return new source.constructor(copyElement(source.buffer), source.byteOffset, source.length);
11329
11330      case '[object ArrayBuffer]':
11331        // Support: IE10
11332        if (!source.slice) {
11333          // If we're in this case we know the environment supports ArrayBuffer
11334          /* eslint-disable no-undef */
11335          var copied = new ArrayBuffer(source.byteLength);
11336          new Uint8Array(copied).set(new Uint8Array(source));
11337          /* eslint-enable */
11338          return copied;
11339        }
11340        return source.slice(0);
11341
11342      case '[object Boolean]':
11343      case '[object Number]':
11344      case '[object String]':
11345      case '[object Date]':
11346        return new source.constructor(source.valueOf());
11347
11348      case '[object RegExp]':
11349        var re = new RegExp(source.source, source.toString().match(/[^/]*$/)[0]);
11350        re.lastIndex = source.lastIndex;
11351        return re;
11352
11353      case '[object Blob]':
11354        return new source.constructor([source], {type: source.type});
11355    }
11356
11357    if (isFunction(source.cloneNode)) {
11358      return source.cloneNode(true);
11359    }
11360  }
11361}
11362
11363
11364/**
11365 * @ngdoc function
11366 * @name angular.equals
11367 * @module ng
11368 * @kind function
11369 *
11370 * @description
11371 * Determines if two objects or two values are equivalent. Supports value types, regular
11372 * expressions, arrays and objects.
11373 *
11374 * Two objects or values are considered equivalent if at least one of the following is true:
11375 *
11376 * * Both objects or values pass `===` comparison.
11377 * * Both objects or values are of the same type and all of their properties are equal by
11378 *   comparing them with `angular.equals`.
11379 * * Both values are NaN. (In JavaScript, NaN == NaN => false. But we consider two NaN as equal)
11380 * * Both values represent the same regular expression (In JavaScript,
11381 *   /abc/ == /abc/ => false. But we consider two regular expressions as equal when their textual
11382 *   representation matches).
11383 *
11384 * During a property comparison, properties of `function` type and properties with names
11385 * that begin with `$` are ignored.
11386 *
11387 * Scope and DOMWindow objects are being compared only by identify (`===`).
11388 *
11389 * @param {*} o1 Object or value to compare.
11390 * @param {*} o2 Object or value to compare.
11391 * @returns {boolean} True if arguments are equal.
11392 *
11393 * @example
11394   <example module="equalsExample" name="equalsExample">
11395     <file name="index.html">
11396      <div ng-controller="ExampleController">
11397        <form novalidate>
11398          <h3>User 1</h3>
11399          Name: <input type="text" ng-model="user1.name">
11400          Age: <input type="number" ng-model="user1.age">
11401
11402          <h3>User 2</h3>
11403          Name: <input type="text" ng-model="user2.name">
11404          Age: <input type="number" ng-model="user2.age">
11405
11406          <div>
11407            <br/>
11408            <input type="button" value="Compare" ng-click="compare()">
11409          </div>
11410          User 1: <pre>{{user1 | json}}</pre>
11411          User 2: <pre>{{user2 | json}}</pre>
11412          Equal: <pre>{{result}}</pre>
11413        </form>
11414      </div>
11415    </file>
11416    <file name="script.js">
11417        angular.module('equalsExample', []).controller('ExampleController', ['$scope', function($scope) {
11418          $scope.user1 = {};
11419          $scope.user2 = {};
11420          $scope.compare = function() {
11421            $scope.result = angular.equals($scope.user1, $scope.user2);
11422          };
11423        }]);
11424    </file>
11425  </example>
11426 */
11427function equals(o1, o2) {
11428  if (o1 === o2) return true;
11429  if (o1 === null || o2 === null) return false;
11430  // eslint-disable-next-line no-self-compare
11431  if (o1 !== o1 && o2 !== o2) return true; // NaN === NaN
11432  var t1 = typeof o1, t2 = typeof o2, length, key, keySet;
11433  if (t1 === t2 && t1 === 'object') {
11434    if (isArray(o1)) {
11435      if (!isArray(o2)) return false;
11436      if ((length = o1.length) === o2.length) {
11437        for (key = 0; key < length; key++) {
11438          if (!equals(o1[key], o2[key])) return false;
11439        }
11440        return true;
11441      }
11442    } else if (isDate(o1)) {
11443      if (!isDate(o2)) return false;
11444      return equals(o1.getTime(), o2.getTime());
11445    } else if (isRegExp(o1)) {
11446      if (!isRegExp(o2)) return false;
11447      return o1.toString() === o2.toString();
11448    } else {
11449      if (isScope(o1) || isScope(o2) || isWindow(o1) || isWindow(o2) ||
11450        isArray(o2) || isDate(o2) || isRegExp(o2)) return false;
11451      keySet = createMap();
11452      for (key in o1) {
11453        if (key.charAt(0) === '$' || isFunction(o1[key])) continue;
11454        if (!equals(o1[key], o2[key])) return false;
11455        keySet[key] = true;
11456      }
11457      for (key in o2) {
11458        if (!(key in keySet) &&
11459            key.charAt(0) !== '$' &&
11460            isDefined(o2[key]) &&
11461            !isFunction(o2[key])) return false;
11462      }
11463      return true;
11464    }
11465  }
11466  return false;
11467}
11468
11469var csp = function() {
11470  if (!isDefined(csp.rules)) {
11471
11472
11473    var ngCspElement = (window.document.querySelector('[ng-csp]') ||
11474                    window.document.querySelector('[data-ng-csp]'));
11475
11476    if (ngCspElement) {
11477      var ngCspAttribute = ngCspElement.getAttribute('ng-csp') ||
11478                    ngCspElement.getAttribute('data-ng-csp');
11479      csp.rules = {
11480        noUnsafeEval: !ngCspAttribute || (ngCspAttribute.indexOf('no-unsafe-eval') !== -1),
11481        noInlineStyle: !ngCspAttribute || (ngCspAttribute.indexOf('no-inline-style') !== -1)
11482      };
11483    } else {
11484      csp.rules = {
11485        noUnsafeEval: noUnsafeEval(),
11486        noInlineStyle: false
11487      };
11488    }
11489  }
11490
11491  return csp.rules;
11492
11493  function noUnsafeEval() {
11494    try {
11495      // eslint-disable-next-line no-new, no-new-func
11496      new Function('');
11497      return false;
11498    } catch (e) {
11499      return true;
11500    }
11501  }
11502};
11503
11504/**
11505 * @ngdoc directive
11506 * @module ng
11507 * @name ngJq
11508 *
11509 * @element ANY
11510 * @param {string=} ngJq the name of the library available under `window`
11511 * to be used for angular.element
11512 * @description
11513 * Use this directive to force the angular.element library.  This should be
11514 * used to force either jqLite by leaving ng-jq blank or setting the name of
11515 * the jquery variable under window (eg. jQuery).
11516 *
11517 * Since angular looks for this directive when it is loaded (doesn't wait for the
11518 * DOMContentLoaded event), it must be placed on an element that comes before the script
11519 * which loads angular. Also, only the first instance of `ng-jq` will be used and all
11520 * others ignored.
11521 *
11522 * @example
11523 * This example shows how to force jqLite using the `ngJq` directive to the `html` tag.
11524 ```html
11525 <!doctype html>
11526 <html ng-app ng-jq>
11527 ...
11528 ...
11529 </html>
11530 ```
11531 * @example
11532 * This example shows how to use a jQuery based library of a different name.
11533 * The library name must be available at the top most 'window'.
11534 ```html
11535 <!doctype html>
11536 <html ng-app ng-jq="jQueryLib">
11537 ...
11538 ...
11539 </html>
11540 ```
11541 */
11542var jq = function() {
11543  if (isDefined(jq.name_)) return jq.name_;
11544  var el;
11545  var i, ii = ngAttrPrefixes.length, prefix, name;
11546  for (i = 0; i < ii; ++i) {
11547    prefix = ngAttrPrefixes[i];
11548    el = window.document.querySelector('[' + prefix.replace(':', '\\:') + 'jq]');
11549    if (el) {
11550      name = el.getAttribute(prefix + 'jq');
11551      break;
11552    }
11553  }
11554
11555  return (jq.name_ = name);
11556};
11557
11558function concat(array1, array2, index) {
11559  return array1.concat(slice.call(array2, index));
11560}
11561
11562function sliceArgs(args, startIndex) {
11563  return slice.call(args, startIndex || 0);
11564}
11565
11566
11567/**
11568 * @ngdoc function
11569 * @name angular.bind
11570 * @module ng
11571 * @kind function
11572 *
11573 * @description
11574 * Returns a function which calls function `fn` bound to `self` (`self` becomes the `this` for
11575 * `fn`). You can supply optional `args` that are prebound to the function. This feature is also
11576 * known as [partial application](http://en.wikipedia.org/wiki/Partial_application), as
11577 * distinguished from [function currying](http://en.wikipedia.org/wiki/Currying#Contrast_with_partial_function_application).
11578 *
11579 * @param {Object} self Context which `fn` should be evaluated in.
11580 * @param {function()} fn Function to be bound.
11581 * @param {...*} args Optional arguments to be prebound to the `fn` function call.
11582 * @returns {function()} Function that wraps the `fn` with all the specified bindings.
11583 */
11584function bind(self, fn) {
11585  var curryArgs = arguments.length > 2 ? sliceArgs(arguments, 2) : [];
11586  if (isFunction(fn) && !(fn instanceof RegExp)) {
11587    return curryArgs.length
11588      ? function() {
11589          return arguments.length
11590            ? fn.apply(self, concat(curryArgs, arguments, 0))
11591            : fn.apply(self, curryArgs);
11592        }
11593      : function() {
11594          return arguments.length
11595            ? fn.apply(self, arguments)
11596            : fn.call(self);
11597        };
11598  } else {
11599    // In IE, native methods are not functions so they cannot be bound (note: they don't need to be).
11600    return fn;
11601  }
11602}
11603
11604
11605function toJsonReplacer(key, value) {
11606  var val = value;
11607
11608  if (typeof key === 'string' && key.charAt(0) === '$' && key.charAt(1) === '$') {
11609    val = undefined;
11610  } else if (isWindow(value)) {
11611    val = '$WINDOW';
11612  } else if (value &&  window.document === value) {
11613    val = '$DOCUMENT';
11614  } else if (isScope(value)) {
11615    val = '$SCOPE';
11616  }
11617
11618  return val;
11619}
11620
11621
11622/**
11623 * @ngdoc function
11624 * @name angular.toJson
11625 * @module ng
11626 * @kind function
11627 *
11628 * @description
11629 * Serializes input into a JSON-formatted string. Properties with leading $$ characters will be
11630 * stripped since angular uses this notation internally.
11631 *
11632 * @param {Object|Array|Date|string|number|boolean} obj Input to be serialized into JSON.
11633 * @param {boolean|number} [pretty=2] If set to true, the JSON output will contain newlines and whitespace.
11634 *    If set to an integer, the JSON output will contain that many spaces per indentation.
11635 * @returns {string|undefined} JSON-ified string representing `obj`.
11636 * @knownIssue
11637 *
11638 * The Safari browser throws a `RangeError` instead of returning `null` when it tries to stringify a `Date`
11639 * object with an invalid date value. The only reliable way to prevent this is to monkeypatch the
11640 * `Date.prototype.toJSON` method as follows:
11641 *
11642 * ```
11643 * var _DatetoJSON = Date.prototype.toJSON;
11644 * Date.prototype.toJSON = function() {
11645 *   try {
11646 *     return _DatetoJSON.call(this);
11647 *   } catch(e) {
11648 *     if (e instanceof RangeError) {
11649 *       return null;
11650 *     }
11651 *     throw e;
11652 *   }
11653 * };
11654 * ```
11655 *
11656 * See https://github.com/angular/angular.js/pull/14221 for more information.
11657 */
11658function toJson(obj, pretty) {
11659  if (isUndefined(obj)) return undefined;
11660  if (!isNumber(pretty)) {
11661    pretty = pretty ? 2 : null;
11662  }
11663  return JSON.stringify(obj, toJsonReplacer, pretty);
11664}
11665
11666
11667/**
11668 * @ngdoc function
11669 * @name angular.fromJson
11670 * @module ng
11671 * @kind function
11672 *
11673 * @description
11674 * Deserializes a JSON string.
11675 *
11676 * @param {string} json JSON string to deserialize.
11677 * @returns {Object|Array|string|number} Deserialized JSON string.
11678 */
11679function fromJson(json) {
11680  return isString(json)
11681      ? JSON.parse(json)
11682      : json;
11683}
11684
11685
11686var ALL_COLONS = /:/g;
11687function timezoneToOffset(timezone, fallback) {
11688  // Support: IE 9-11 only, Edge 13-14+
11689  // IE/Edge do not "understand" colon (`:`) in timezone
11690  timezone = timezone.replace(ALL_COLONS, '');
11691  var requestedTimezoneOffset = Date.parse('Jan 01, 1970 00:00:00 ' + timezone) / 60000;
11692  return isNumberNaN(requestedTimezoneOffset) ? fallback : requestedTimezoneOffset;
11693}
11694
11695
11696function addDateMinutes(date, minutes) {
11697  date = new Date(date.getTime());
11698  date.setMinutes(date.getMinutes() + minutes);
11699  return date;
11700}
11701
11702
11703function convertTimezoneToLocal(date, timezone, reverse) {
11704  reverse = reverse ? -1 : 1;
11705  var dateTimezoneOffset = date.getTimezoneOffset();
11706  var timezoneOffset = timezoneToOffset(timezone, dateTimezoneOffset);
11707  return addDateMinutes(date, reverse * (timezoneOffset - dateTimezoneOffset));
11708}
11709
11710
11711/**
11712 * @returns {string} Returns the string representation of the element.
11713 */
11714function startingTag(element) {
11715  element = jqLite(element).clone();
11716  try {
11717    // turns out IE does not let you set .html() on elements which
11718    // are not allowed to have children. So we just ignore it.
11719    element.empty();
11720  } catch (e) { /* empty */ }
11721  var elemHtml = jqLite('<div>').append(element).html();
11722  try {
11723    return element[0].nodeType === NODE_TYPE_TEXT ? lowercase(elemHtml) :
11724        elemHtml.
11725          match(/^(<[^>]+>)/)[1].
11726          replace(/^<([\w-]+)/, function(match, nodeName) {return '<' + lowercase(nodeName);});
11727  } catch (e) {
11728    return lowercase(elemHtml);
11729  }
11730
11731}
11732
11733
11734/////////////////////////////////////////////////
11735
11736/**
11737 * Tries to decode the URI component without throwing an exception.
11738 *
11739 * @private
11740 * @param str value potential URI component to check.
11741 * @returns {boolean} True if `value` can be decoded
11742 * with the decodeURIComponent function.
11743 */
11744function tryDecodeURIComponent(value) {
11745  try {
11746    return decodeURIComponent(value);
11747  } catch (e) {
11748    // Ignore any invalid uri component.
11749  }
11750}
11751
11752
11753/**
11754 * Parses an escaped url query string into key-value pairs.
11755 * @returns {Object.<string,boolean|Array>}
11756 */
11757function parseKeyValue(/**string*/keyValue) {
11758  var obj = {};
11759  forEach((keyValue || '').split('&'), function(keyValue) {
11760    var splitPoint, key, val;
11761    if (keyValue) {
11762      key = keyValue = keyValue.replace(/\+/g,'%20');
11763      splitPoint = keyValue.indexOf('=');
11764      if (splitPoint !== -1) {
11765        key = keyValue.substring(0, splitPoint);
11766        val = keyValue.substring(splitPoint + 1);
11767      }
11768      key = tryDecodeURIComponent(key);
11769      if (isDefined(key)) {
11770        val = isDefined(val) ? tryDecodeURIComponent(val) : true;
11771        if (!hasOwnProperty.call(obj, key)) {
11772          obj[key] = val;
11773        } else if (isArray(obj[key])) {
11774          obj[key].push(val);
11775        } else {
11776          obj[key] = [obj[key],val];
11777        }
11778      }
11779    }
11780  });
11781  return obj;
11782}
11783
11784function toKeyValue(obj) {
11785  var parts = [];
11786  forEach(obj, function(value, key) {
11787    if (isArray(value)) {
11788      forEach(value, function(arrayValue) {
11789        parts.push(encodeUriQuery(key, true) +
11790                   (arrayValue === true ? '' : '=' + encodeUriQuery(arrayValue, true)));
11791      });
11792    } else {
11793    parts.push(encodeUriQuery(key, true) +
11794               (value === true ? '' : '=' + encodeUriQuery(value, true)));
11795    }
11796  });
11797  return parts.length ? parts.join('&') : '';
11798}
11799
11800
11801/**
11802 * We need our custom method because encodeURIComponent is too aggressive and doesn't follow
11803 * http://www.ietf.org/rfc/rfc3986.txt with regards to the character set (pchar) allowed in path
11804 * segments:
11805 *    segment       = *pchar
11806 *    pchar         = unreserved / pct-encoded / sub-delims / ":" / "@"
11807 *    pct-encoded   = "%" HEXDIG HEXDIG
11808 *    unreserved    = ALPHA / DIGIT / "-" / "." / "_" / "~"
11809 *    sub-delims    = "!" / "$" / "&" / "'" / "(" / ")"
11810 *                     / "*" / "+" / "," / ";" / "="
11811 */
11812function encodeUriSegment(val) {
11813  return encodeUriQuery(val, true).
11814             replace(/%26/gi, '&').
11815             replace(/%3D/gi, '=').
11816             replace(/%2B/gi, '+');
11817}
11818
11819
11820/**
11821 * This method is intended for encoding *key* or *value* parts of query component. We need a custom
11822 * method because encodeURIComponent is too aggressive and encodes stuff that doesn't have to be
11823 * encoded per http://tools.ietf.org/html/rfc3986:
11824 *    query         = *( pchar / "/" / "?" )
11825 *    pchar         = unreserved / pct-encoded / sub-delims / ":" / "@"
11826 *    unreserved    = ALPHA / DIGIT / "-" / "." / "_" / "~"
11827 *    pct-encoded   = "%" HEXDIG HEXDIG
11828 *    sub-delims    = "!" / "$" / "&" / "'" / "(" / ")"
11829 *                     / "*" / "+" / "," / ";" / "="
11830 */
11831function encodeUriQuery(val, pctEncodeSpaces) {
11832  return encodeURIComponent(val).
11833             replace(/%40/gi, '@').
11834             replace(/%3A/gi, ':').
11835             replace(/%24/g, '$').
11836             replace(/%2C/gi, ',').
11837             replace(/%3B/gi, ';').
11838             replace(/%20/g, (pctEncodeSpaces ? '%20' : '+'));
11839}
11840
11841var ngAttrPrefixes = ['ng-', 'data-ng-', 'ng:', 'x-ng-'];
11842
11843function getNgAttribute(element, ngAttr) {
11844  var attr, i, ii = ngAttrPrefixes.length;
11845  for (i = 0; i < ii; ++i) {
11846    attr = ngAttrPrefixes[i] + ngAttr;
11847    if (isString(attr = element.getAttribute(attr))) {
11848      return attr;
11849    }
11850  }
11851  return null;
11852}
11853
11854function allowAutoBootstrap(document) {
11855  var script = document.currentScript;
11856
11857  if (!script) {
11858    // IE does not have `document.currentScript`
11859    return true;
11860  }
11861
11862  // If the `currentScript` property has been clobbered just return false, since this indicates a probable attack
11863  if (!(script instanceof window.HTMLScriptElement || script instanceof window.SVGScriptElement)) {
11864    return false;
11865  }
11866
11867  var attributes = script.attributes;
11868  var srcs = [attributes.getNamedItem('src'), attributes.getNamedItem('href'), attributes.getNamedItem('xlink:href')];
11869
11870  return srcs.every(function(src) {
11871    if (!src) {
11872      return true;
11873    }
11874    if (!src.value) {
11875      return false;
11876    }
11877
11878    var link = document.createElement('a');
11879    link.href = src.value;
11880
11881    if (document.location.origin === link.origin) {
11882      // Same-origin resources are always allowed, even for non-whitelisted schemes.
11883      return true;
11884    }
11885    // Disabled bootstrapping unless angular.js was loaded from a known scheme used on the web.
11886    // This is to prevent angular.js bundled with browser extensions from being used to bypass the
11887    // content security policy in web pages and other browser extensions.
11888    switch (link.protocol) {
11889      case 'http:':
11890      case 'https:':
11891      case 'ftp:':
11892      case 'blob:':
11893      case 'file:':
11894      case 'data:':
11895        return true;
11896      default:
11897        return false;
11898    }
11899  });
11900}
11901
11902// Cached as it has to run during loading so that document.currentScript is available.
11903var isAutoBootstrapAllowed = allowAutoBootstrap(window.document);
11904
11905/**
11906 * @ngdoc directive
11907 * @name ngApp
11908 * @module ng
11909 *
11910 * @element ANY
11911 * @param {angular.Module} ngApp an optional application
11912 *   {@link angular.module module} name to load.
11913 * @param {boolean=} ngStrictDi if this attribute is present on the app element, the injector will be
11914 *   created in "strict-di" mode. This means that the application will fail to invoke functions which
11915 *   do not use explicit function annotation (and are thus unsuitable for minification), as de
11915scribed
11916 *   in {@link guide/di the Dependency Injection guide}, and useful debugging info will assist in
11917 *   tracking down the root of these bugs.
11918 *
11919 * @description
11920 *
11921 * Use this directive to **auto-bootstrap** an AngularJS application. The `ngApp` directive
11922 * designates the **root element** of the application and is typically placed near the root element
11923 * of the page - e.g. on the `<body>` or `<html>` tags.
11924 *
11925 * There are a few things to keep in mind when using `ngApp`:
11926 * - only one AngularJS application can be auto-bootstrapped per HTML document. The first `ngApp`
11927 *   found in the document will be used to define the root element to auto-bootstrap as an
11928 *   application. To run multiple applications in an HTML document you must manually bootstrap them using
11929 *   {@link angular.bootstrap} instead.
11930 * - AngularJS applications cannot be nested within each other.
11931 * - Do not use a directive that uses {@link ng.$compile#transclusion transclusion} on the same element as `ngApp`.
11932 *   This includes directives such as {@link ng.ngIf `ngIf`}, {@link ng.ngInclude `ngInclude`} and
11933 *   {@link ngRoute.ngView `ngView`}.
11934 *   Doing this misplaces the app {@link ng.$rootElement `$rootElement`} and the app's {@link auto.$injector injector},
11935 *   causing animations to stop working and making the injector inaccessible from outside the app.
11936 *
11937 * You can specify an **AngularJS module** to be used as the root module for the application.  This
11938 * module will be loaded into the {@link auto.$injector} when the application is bootstrapped. It
11939 * should contain the application code needed or have dependencies on other modules that will
11940 * contain the code. See {@link angular.module} for more information.
11941 *
11942 * In the example below if the `ngApp` directive were not placed on the `html` element then the
11943 * document would not be compiled, the `AppController` would not be instantiated and the `{{ a+b }}`
11944 * would not be resolved to `3`.
11945 *
11946 * `ngApp` is the easiest, and most common way to bootstrap an application.
11947 *
11948 <example module="ngAppDemo" name="ng-app">
11949   <file name="index.html">
11950   <div ng-controller="ngAppDemoController">
11951     I can add: {{a}} + {{b}} =  {{ a+b }}
11952   </div>
11953   </file>
11954   <file name="script.js">
11955   angular.module('ngAppDemo', []).controller('ngAppDemoController', function($scope) {
11956     $scope.a = 1;
11957     $scope.b = 2;
11958   });
11959   </file>
11960 </example>
11961 *
11962 * Using `ngStrictDi`, you would see something like this:
11963 *
11964 <example ng-app-included="true" name="strict-di">
11965   <file name="index.html">
11966   <div ng-app="ngAppStrictDemo" ng-strict-di>
11967       <div ng-controller="GoodController1">
11968           I can add: {{a}} + {{b}} =  {{ a+b }}
11969
11970           <p>This renders because the controller does not fail to
11971              instantiate, by using explicit annotation style (see
11972              script.js for details)
11973           </p>
11974       </div>
11975
11976       <div ng-controller="GoodController2">
11977           Name: <input ng-model="name"><br />
11978           Hello, {{name}}!
11979
11980           <p>This renders because the controller does not fail to
11981              instantiate, by using explicit annotation style
11982              (see script.js for details)
11983           </p>
11984       </div>
11985
11986       <div ng-controller="BadController">
11987           I can add: {{a}} + {{b}} =  {{ a+b }}
11988
11989           <p>The controller could not be instantiated, due to relying
11990              on automatic function annotations (which are disabled in
11991              strict mode). As such, the content of this section is not
11992              interpolated, and there should be an error in your web console.
11993           </p>
11994       </div>
11995   </div>
11996   </file>
11997   <file name="script.js">
11998   angular.module('ngAppStrictDemo', [])
11999     // BadController will fail to instantiate, due to relying on automatic function annotation,
12000     // rather than an explicit annotation
12001     .controller('BadController', function($scope) {
12002       $scope.a = 1;
12003       $scope.b = 2;
12004     })
12005     // Unlike BadController, GoodController1 and GoodController2 will not fail to be instantiated,
12006     // due to using explicit annotations using the array style and $inject property, respectively.
12007     .controller('GoodController1', ['$scope', function($scope) {
12008       $scope.a = 1;
12009       $scope.b = 2;
12010     }])
12011     .controller('GoodController2', GoodController2);
12012     function GoodController2($scope) {
12013       $scope.name = 'World';
12014     }
12015     GoodController2.$inject = ['$scope'];
12016   </file>
12017   <file name="style.css">
12018   div[ng-controller] {
12019       margin-bottom: 1em;
12020       -webkit-border-radius: 4px;
12021       border-radius: 4px;
12022       border: 1px solid;
12023       padding: .5em;
12024   }
12025   div[ng-controller^=Good] {
12026       border-color: #d6e9c6;
12027       background-color: #dff0d8;
12028       color: #3c763d;
12029   }
12030   div[ng-controller^=Bad] {
12031       border-color: #ebccd1;
12032       background-color: #f2dede;
12033       color: #a94442;
12034       margin-bottom: 0;
12035   }
12036   </file>
12037 </example>
12038 */
12039function angularInit(element, bootstrap) {
12040  var appElement,
12041      module,
12042      config = {};
12043
12044  // The element `element` has priority over any other element.
12045  forEach(ngAttrPrefixes, function(prefix) {
12046    var name = prefix + 'app';
12047
12048    if (!appElement && element.hasAttribute && element.hasAttribute(name)) {
12049      appElement = element;
12050      module = element.getAttribute(name);
12051    }
12052  });
12053  forEach(ngAttrPrefixes, function(prefix) {
12054    var name = prefix + 'app';
12055    var candidate;
12056
12057    if (!appElement && (candidate = element.querySelector('[' + name.replace(':', '\\:') + ']'))) {
12058      appElement = candidate;
12059      module = candidate.getAttribute(name);
12060    }
12061  });
12062  if (appElement) {
12063    if (!isAutoBootstrapAllowed) {
12064      window.console.error('Angular: disabling automatic bootstrap. <script> protocol indicates ' +
12065          'an extension, document.location.href does not match.');
12066      return;
12067    }
12068    config.strictDi = getNgAttribute(appElement, 'strict-di') !== null;
12069    bootstrap(appElement, module ? [module] : [], config);
12070  }
12071}
12072
12073/**
12074 * @ngdoc function
12075 * @name angular.bootstrap
12076 * @module ng
12077 * @description
12078 * Use this function to manually start up angular application.
12079 *
12080 * For more information, see the {@link guide/bootstrap Bootstrap guide}.
12081 *
12082 * Angular will detect if it has been loaded into the browser more than once and only allow the
12083 * first loaded script to be bootstrapped and will report a warning to the browser console for
12084 * each of the subsequent scripts. This prevents strange results in applications, where otherwise
12085 * multiple instances of Angular try to work on the DOM.
12086 *
12087 * <div class="alert alert-warning">
12088 * **Note:** Protractor based end-to-end tests cannot use this function to bootstrap manually.
12089 * They must use {@link ng.directive:ngApp ngApp}.
12090 * </div>
12091 *
12092 * <div class="alert alert-warning">
12093 * **Note:** Do not bootstrap the app on an element with a directive that uses {@link ng.$compile#transclusion transclusion},
12094 * such as {@link ng.ngIf `ngIf`}, {@link ng.ngInclude `ngInclude`} and {@link ngRoute.ngView `ngView`}.
12095 * Doing this misplaces the app {@link ng.$rootElement `$rootElement`} and the app's {@link auto.$injector injector},
12096 * causing animations to stop working and making the injector inaccessible from outside the app.
12097 * </div>
12098 *
12099 * ```html
12100 * <!doctype html>
12101 * <html>
12102 * <body>
12103 * <div ng-controller="WelcomeController">
12104 *   {{greeting}}
12105 * </div>
12106 *
12107 * <script src="angular.js"></script>
12108 * <script>
12109 *   var app = angular.module('demo', [])
12110 *   .controller('WelcomeController', function($scope) {
12111 *       $scope.greeting = 'Welcome!';
12112 *   });
12113 *   angular.bootstrap(document, ['demo']);
12114 * </script>
12115 * </body>
12116 * </html>
12117 * ```
12118 *
12119 * @param {DOMElement} element DOM element which is the root of angular application.
12120 * @param {Array<String|Function|Array>=} modules an array of modules to load into the application.
12121 *     Each item in the array should be the name of a predefined module or a (DI annotated)
12122 *     function that will be invoked by the injector as a `config` block.
12123 *     See: {@link angular.module modules}
12124 * @param {Object=} config an object for defining configuration options for the application. The
12125 *     following keys are supported:
12126 *
12127 * * `strictDi` - disable automatic function annotation for the application. This is meant to
12128 *   assist in finding bugs which break minified code. Defaults to `false`.
12129 *
12130 * @returns {auto.$injector} Returns the newly created injector for this app.
12131 */
12132function bootstrap(element, modules, config) {
12133  if (!isObject(config)) config = {};
12134  var defaultConfig = {
12135    strictDi: false
12136  };
12137  config = extend(defaultConfig, config);
12138  var doBootstrap = function() {
12139    element = jqLite(element);
12140
12141    if (element.injector()) {
12142      var tag = (element[0] === window.document) ? 'document' : startingTag(element);
12143      // Encode angle brackets to prevent input from being sanitized to empty string #8683.
12144      throw ngMinErr(
12145          'btstrpd',
12146          'App already bootstrapped with this element \'{0}\'',
12147          tag.replace(/</,'&lt;').replace(/>/,'&gt;'));
12148    }
12149
12150    modules = modules || [];
12151    modules.unshift(['$provide', function($provide) {
12152      $provide.value('$rootElement', element);
12153    }]);
12154
12155    if (config.debugInfoEnabled) {
12156      // Pushing so that this overrides `debugInfoEnabled` setting defined in user's `modules`.
12157      modules.push(['$compileProvider', function($compileProvider) {
12158        $compileProvider.debugInfoEnabled(true);
12159      }]);
12160    }
12161
12162    modules.unshift('ng');
12163    var injector = createInjector(modules, config.strictDi);
12164    injector.invoke(['$rootScope', '$rootElement', '$compile', '$injector',
12165       function bootstrapApply(scope, element, compile, injector) {
12166        scope.$apply(function() {
12167          element.data('$injector', injector);
12168          compile(element)(scope);
12169        });
12170      }]
12171    );
12172    return injector;
12173  };
12174
12175  var NG_ENABLE_DEBUG_INFO = /^NG_ENABLE_DEBUG_INFO!/;
12176  var NG_DEFER_BOOTSTRAP = /^NG_DEFER_BOOTSTRAP!/;
12177
12178  if (window && NG_ENABLE_DEBUG_INFO.test(window.name)) {
12179    config.debugInfoEnabled = true;
12180    window.name = window.name.replace(NG_ENABLE_DEBUG_INFO, '');
12181  }
12182
12183  if (window && !NG_DEFER_BOOTSTRAP.test(window.name)) {
12184    return doBootstrap();
12185  }
12186
12187  window.name = window.name.replace(NG_DEFER_BOOTSTRAP, '');
12188  angular.resumeBootstrap = function(extraModules) {
12189    forEach(extraModules, function(module) {
12190      modules.push(module);
12191    });
12192    return doBootstrap();
12193  };
12194
12195  if (isFunction(angular.resumeDeferredBootstrap)) {
12196    angular.resumeDeferredBootstrap();
12197  }
12198}
12199
12200/**
12201 * @ngdoc function
12202 * @name angular.reloadWithDebugInfo
12203 * @module ng
12204 * @description
12205 * Use this function to reload the current application with debug information turned on.
12206 * This takes precedence over a call to `$compileProvider.debugInfoEnabled(false)`.
12207 *
12208 * See {@link ng.$compileProvider#debugInfoEnabled} for more.
12209 */
12210function reloadWithDebugInfo() {
12211  window.name = 'NG_ENABLE_DEBUG_INFO!' + window.name;
12212  window.location.reload();
12213}
12214
12215/**
12216 * @name angular.getTestability
12217 * @module ng
12218 * @description
12219 * Get the testability service for the instance of Angular on the given
12220 * element.
12221 * @param {DOMElement} element DOM element which is the root of angular application.
12222 */
12223function getTestability(rootElement) {
12224  var injector = angular.element(rootElement).injector();
12225  if (!injector) {
12226    throw ngMinErr('test',
12227      'no injector found for element argument to getTestability');
12228  }
12229  return injector.get('$$testability');
12230}
12231
12232var SNAKE_CASE_REGEXP = /[A-Z]/g;
12233function snake_case(name, separator) {
12234  separator = separator || '_';
12235  return name.replace(SNAKE_CASE_REGEXP, function(letter, pos) {
12236    return (pos ? separator : '') + letter.toLowerCase();
12237  });
12238}
12239
12240var bindJQueryFired = false;
vendor: 9,918 bytes, lines 12241-12557
12241function bindJQuery() {
12242  var originalCleanData;
12243
12244  if (bindJQueryFired) {
12245    return;
12246  }
12247
12248  // bind to jQuery if present;
12249  var jqName = jq();
12250  jQuery = isUndefined(jqName) ? window.jQuery :   // use jQuery (if present)
12251           !jqName             ? undefined     :   // use jqLite
12252                                 window[jqName];   // use jQuery specified by `ngJq`
12253
12254  // Use jQuery if it exists with proper functionality, otherwise default to us.
12255  // Angular 1.2+ requires jQuery 1.7+ for on()/off() support.
12256  // Angular 1.3+ technically requires at least jQuery 2.1+ but it may work with older
12257  // versions. It will not work for sure with jQuery <1.7, though.
12258  if (jQuery && jQuery.fn.on) {
12259    jqLite = jQuery;
12260    extend(jQuery.fn, {
12261      scope: JQLitePrototype.scope,
12262      isolateScope: JQLitePrototype.isolateScope,
12263      controller: /** @type {?} */ (JQLitePrototype).controller,
12264      injector: JQLitePrototype.injector,
12265      inheritedData: JQLitePrototype.inheritedData
12266    });
12267
12268    // All nodes removed from the DOM via various jQuery APIs like .remove()
12269    // are passed through jQuery.cleanData. Monkey-patch this method to fire
12270    // the $destroy event on all removed nodes.
12271    originalCleanData = jQuery.cleanData;
12272    jQuery.cleanData = function(elems) {
12273      var events;
12274      for (var i = 0, elem; (elem = elems[i]) != null; i++) {
12275        events = jQuery._data(elem, 'events');
12276        if (events && events.$destroy) {
12277          jQuery(elem).triggerHandler('$destroy');
12278        }
12279      }
12280      originalCleanData(elems);
12281    };
12282  } else {
12283    jqLite = JQLite;
12284  }
12285
12286  angular.element = jqLite;
12287
12288  // Prevent double-proxying.
12289  bindJQueryFired = true;
12290}
12291
12292/**
12293 * throw error if the argument is falsy.
12294 */
12295function assertArg(arg, name, reason) {
12296  if (!arg) {
12297    throw ngMinErr('areq', 'Argument \'{0}\' is {1}', (name || '?'), (reason || 'required'));
12298  }
12299  return arg;
12300}
12301
12302function assertArgFn(arg, name, acceptArrayAnnotation) {
12303  if (acceptArrayAnnotation && isArray(arg)) {
12304      arg = arg[arg.length - 1];
12305  }
12306
12307  assertArg(isFunction(arg), name, 'not a function, got ' +
12308      (arg && typeof arg === 'object' ? arg.constructor.name || 'Object' : typeof arg));
12309  return arg;
12310}
12311
12312/**
12313 * throw error if the name given is hasOwnProperty
12314 * @param  {String} name    the name to test
12315 * @param  {String} context the context in which the name is used, such as module or directive
12316 */
12317function assertNotHasOwnProperty(name, context) {
12318  if (name === 'hasOwnProperty') {
12319    throw ngMinErr('badname', 'hasOwnProperty is not a valid {0} name', context);
12320  }
12321}
12322
12323/**
12324 * Return the value accessible from the object by path. Any undefined traversals are ignored
12325 * @param {Object} obj starting object
12326 * @param {String} path path to traverse
12327 * @param {boolean} [bindFnToScope=true]
12328 * @returns {Object} value as accessible by path
12329 */
12330//TODO(misko): this function needs to be removed
12331function getter(obj, path, bindFnToScope) {
12332  if (!path) return obj;
12333  var keys = path.split('.');
12334  var key;
12335  var lastInstance = obj;
12336  var len = keys.length;
12337
12338  for (var i = 0; i < len; i++) {
12339    key = keys[i];
12340    if (obj) {
12341      obj = (lastInstance = obj)[key];
12342    }
12343  }
12344  if (!bindFnToScope && isFunction(obj)) {
12345    return bind(lastInstance, obj);
12346  }
12347  return obj;
12348}
12349
12350/**
12351 * Return the DOM siblings between the first and last node in the given array.
12352 * @param {Array} array like object
12353 * @returns {Array} the inputted object or a jqLite collection containing the nodes
12354 */
12355function getBlockNodes(nodes) {
12356  // TODO(perf): update `nodes` instead of creating a new object?
12357  var node = nodes[0];
12358  var endNode = nodes[nodes.length - 1];
12359  var blockNodes;
12360
12361  for (var i = 1; node !== endNode && (node = node.nextSibling); i++) {
12362    if (blockNodes || nodes[i] !== node) {
12363      if (!blockNodes) {
12364        blockNodes = jqLite(slice.call(nodes, 0, i));
12365      }
12366      blockNodes.push(node);
12367    }
12368  }
12369
12370  return blockNodes || nodes;
12371}
12372
12373
12374/**
12375 * Creates a new object without a prototype. This object is useful for lookup without having to
12376 * guard against prototypically inherited properties via hasOwnProperty.
12377 *
12378 * Related micro-benchmarks:
12379 * - http://jsperf.com/object-create2
12380 * - http://jsperf.com/proto-map-lookup/2
12381 * - http://jsperf.com/for-in-vs-object-keys2
12382 *
12383 * @returns {Object}
12384 */
12385function createMap() {
12386  return Object.create(null);
12387}
12388
12389function stringify(value) {
12390  if (value == null) { // null || undefined
12391    return '';
12392  }
12393  switch (typeof value) {
12394    case 'string':
12395      break;
12396    case 'number':
12397      value = '' + value;
12398      break;
12399    default:
12400      if (hasCustomToString(value) && !isArray(value) && !isDate(value)) {
12401        value = value.toString();
12402      } else {
12403        value = toJson(value);
12404      }
12405  }
12406
12407  return value;
12408}
12409
12410var NODE_TYPE_ELEMENT = 1;
12411var NODE_TYPE_ATTRIBUTE = 2;
12412var NODE_TYPE_TEXT = 3;
12413var NODE_TYPE_COMMENT = 8;
12414var NODE_TYPE_DOCUMENT = 9;
12415var NODE_TYPE_DOCUMENT_FRAGMENT = 11;
12416
12417/**
12418 * @ngdoc type
12419 * @name angular.Module
12420 * @module ng
12421 * @description
12422 *
12423 * Interface for configuring angular {@link angular.module modules}.
12424 */
12425
12426function setupModuleLoader(window) {
12427
12428  var $injectorMinErr = minErr('$injector');
12429  var ngMinErr = minErr('ng');
12430
12431  function ensure(obj, name, factory) {
12432    return obj[name] || (obj[name] = factory());
12433  }
12434
12435  var angular = ensure(window, 'angular', Object);
12436
12437  // We need to expose `angular.$$minErr` to modules such as `ngResource` that reference it during bootstrap
12438  angular.$$minErr = angular.$$minErr || minErr;
12439
12440  return ensure(angular, 'module', function() {
12441    /** @type {Object.<string, angular.Module>} */
12442    var modules = {};
12443
12444    /**
12445     * @ngdoc function
12446     * @name angular.module
12447     * @module ng
12448     * @description
12449     *
12450     * The `angular.module` is a global place for creating, registering and retrieving Angular
12451     * modules.
12452     * All modules (angular core or 3rd party) that should be available to an application must be
12453     * registered using this mechanism.
12454     *
12455     * Passing one argument retrieves an existing {@link angular.Module},
12456     * whereas passing more than one argument creates a new {@link angular.Module}
12457     *
12458     *
12459     * # Module
12460     *
12461     * A module is a collection of services, directives, controllers, filters, and configuration information.
12462     * `angular.module` is used to configure the {@link auto.$injector $injector}.
12463     *
12464     * ```js
12465     * // Create a new module
12466     * var myModule = angular.module('myModule', []);
12467     *
12468     * // register a new service
12469     * myModule.value('appName', 'MyCoolApp');
12470     *
12471     * // configure existing services inside initialization blocks.
12472     * myModule.config(['$locationProvider', function($locationProvider) {
12473     *   // Configure existing providers
12474     *   $locationProvider.hashPrefix('!');
12475     * }]);
12476     * ```
12477     *
12478     * Then you can create an injector and load your modules like this:
12479     *
12480     * ```js
12481     * var injector = angular.injector(['ng', 'myModule'])
12482     * ```
12483     *
12484     * However it's more likely that you'll just use
12485     * {@link ng.directive:ngApp ngApp} or
12486     * {@link angular.bootstrap} to simplify this process for you.
12487     *
12488     * @param {!string} name The name of the module to create or retrieve.
12489     * @param {!Array.<string>=} requires If specified then new module is being created. If
12490     *        unspecified then the module is being retrieved for further configuration.
12491     * @param {Function=} configFn Optional configuration function for the module. Same as
12492     *        {@link angular.Module#config Module#config()}.
12493     * @returns {angular.Module} new module with the {@link angular.Module} api.
12494     */
12495    return function module(name, requires, configFn) {
12496
12497      var info = {};
12498
12499      var assertNotHasOwnProperty = function(name, context) {
12500        if (name === 'hasOwnProperty') {
12501          throw ngMinErr('badname', 'hasOwnProperty is not a valid {0} name', context);
12502        }
12503      };
12504
12505      assertNotHasOwnProperty(name, 'module');
12506      if (requires && modules.hasOwnProperty(name)) {
12507        modules[name] = null;
12508      }
12509      return ensure(modules, name, function() {
12510        if (!requires) {
12511          throw $injectorMinErr('nomod', 'Module \'{0}\' is not available! You either misspelled ' +
12512             'the module name or forgot to load it. If registering a module ensure that you ' +
12513             'specify the dependencies as the second argument.', name);
12514        }
12515
12516        /** @type {!Array.<Array.<*>>} */
12517        var invokeQueue = [];
12518
12519        /** @type {!Array.<Function>} */
12520        var configBlocks = [];
12521
12522        /** @type {!Array.<Function>} */
12523        var runBlocks = [];
12524
12525        var config = invokeLater('$injector', 'invoke', 'push', configBlocks);
12526
12527        /** @type {angular.Module} */
12528        var moduleInstance = {
12529          // Private state
12530          _invokeQueue: invokeQueue,
12531          _configBlocks: configBlocks,
12532          _runBlocks: runBlocks,
12533
12534          /**
12535           * @ngdoc method
12536           * @name angular.Module#info
12537           * @module ng
12538           *
12539           * @param {Object=} info Information about the module
12540           * @returns {Object|Module} The current info object for this module if called as a getter,
12541           *                          or `this` if called as a setter.
12542           *
12543           * @description
12544           * Read and write custom information about this module.
12545           * For example you could put the version of the module in here.
12546           *
12547           * ```js
12548           * angular.module('myModule', []).info({ version: '1.0.0' });
12549           * ```
12550           *
12551           * The version could then be read back out by accessing the module elsewhere:
12552           *
12553           * ```
12554           * var version = angular.module('myModule').info().version;
12555           * ```
12556           *
12557           * You can also retrieve this information during runtime via the
12558           * {@link $injector#modules `$injector.modules`} property:
12559           *
12560           * ```js
12561           * var version = $injector.modules['myModule'].info().version;
12562           * ```
12563           */
12564          info: function(value) {
12565            if (isDefined(value)) {
12566              if (!isObject(value)) throw ngMinErr('aobj', 'Argument \'{0}\' must be an object', 'value');
12567              info = value;
12568              return this;
12569            }
12570            return info;
12571          },
12572
12573          /**
12574           * @ngdoc property
12575           * @name angular.Module#requires
12576           * @module ng
12577           *
12578           * @description
12579           * Holds the list of modules which the injector will load before the current module is
12580           * loaded.
12581           */
12582          requires: requires,
12583
12584          /**
12585           * @ngdoc property
12586           * @name angular.Module#name
12587           * @module ng
12588           *
12589           * @description
12590           * Name of the module.
12591           */
12592          name: name,
12593
12594
12595          /**
12596           * @ngdoc method
12597           * @name angular.Module#provider
12598           * @module ng
12599           * @param {string} name service name
12600           * @param {Function} providerType Construction function for creating new instance of the
12601           *                                service.
12602           * @description
12603           * See {@link auto.$provide#provider $provide.provider()}.
12604           */
12605          provider: invokeLaterAndSetModuleName('$provide', 'provider'),
12606
12607          /**
12608           * @ngdoc method
12609           * @name angular.Module#factory
12610           * @module ng
12611           * @param {string} name service name
12612           * @param {Function} providerFunction Function for creating new instance of the service.
12613           * @description
12614           * See {@link auto.$provide#factory $provide.factory()}.
12615           */
12616          factory: invokeLaterAndSetModuleName('$provide', 'factory'),
12617
12618          /**
12619           * @ngdoc method
12620           * @name angular.Module#service
12621           * @module ng
12622           * @param {string} name service name
12623           * @param {Function} constructor A constructor function that will be instantiated.
12624           * @description
12625           * See {@link auto.$provide#service $provide.service()}.
12626           */
12627          service: invokeLaterAndSetModuleName('$provide', 'service'),
12628
12629          /**
12630           * @ngdoc method
12631           * @name angular.Module#value
12632           * @module ng
12633           * @param {string} name service name
12634           * @param {*} object Service instance object.
12635           * @description
12636           * See {@link auto.$provide#value $provide.value()}.
12637           */
12638          value: invokeLater('$provide', 'value'),
12639
12640          /**
12641           * @ngdoc method
12642           * @name angular.Module#constant
12643           * @module ng
12644           * @param {string} name constant name
12645           * @param {*} object Constant value.
12646           * @description
12647           * Because the constants are fixed, they get applied before other provide methods.
12648           * See {@link auto.$provide#constant $provide.constant()}.
12649           */
12650          constant: invokeLater('$provide', 'constant', 'unshift'),
12651
12652           /**
12653           * @ngdoc method
12654           * @name angular.Module#decorator
12655           * @module ng
12656           * @param {string} name The name of the service to decorate.
12657           * @param {Function} decorFn This function will be invoked when the service needs to be
12658           *                           instantiated and should return the decorated service instance.
12659           * @description
12660           * See {@link auto.$provide#decorator $provide.decorator()}.
12661           */
12662          decorator: invokeLaterAndSetModuleName('$provide', 'decorator', configBlocks),
12663
12664          /**
12665           * @ngdoc method
12666           * @name angular.Module#animation
12667           * @module ng
12668           * @param {string} name animation name
12669           * @param {Function} animationFactory Factory function for creating new instance of an
12670           *                                    animation.
12671           * @description
12672           *
12673           * **NOTE**: animations take effect only if the **ngAnimate** module is loaded.
12674           *
12675           *
12676           * Defines an animation hook that can be later used with
12677           * {@link $animate $animate} service and directives that use this service.
12678           *
12679           * ```js
12680           * module.animation('.animation-name', function($inject1, $inject2) {
12681           *   return {
12682           *     eventName : function(element, done) {
12683           *       //code to run the animation
12684           *       //once complete, then run done()
12685           *       return function cancellationFunction(element) {
12686           *         //code to cancel the animation
12687           *       }
12688           *     }
12689           *   }
12690           * })
12691           * ```
12692           *
12693           * See {@link ng.$animateProvider#register $animateProvider.register()} and
12694           * {@link ngAnimate ngAnimate module} for more information.
12695           */
12696          animation: invokeLaterAndSetModuleName('$animateProvider', 'register'),
12697
12698          /**
12699           * @ngdoc method
12700           * @name angular.Module#filter
12701           * @module ng
12702           * @param {string} name Filter name - this must be a valid angular expression identifier
12703           * @param {Function} filterFactory Factory function for creating new instance of filter.
12704           * @description
12705           * See {@link ng.$filterProvider#register $filterProvider.register()}.
12706           *
12707           * <div class="alert alert-warning">
12708           * **Note:** Filter names must be valid angular {@link expression} identifiers, such as `uppercase` or `orderBy`.
12709           * Names with special characters, such as hyphens and dots, are not allowed. If you wish to namespace
12710           * your filters, then you can use capitalization (`myappSubsectionFilterx`) or underscores
12711           * (`myapp_subsection_filterx`).
12712           * </div>
12713           */
12714          filter: invokeLaterAndSetModuleName('$filterProvider', 'register'),
12715
12716          /**
12717           * @ngdoc method
12718           * @name angular.Module#controller
12719           * @module ng
12720           * @param {string|Object} name Controller name, or an object map of controllers where the
12721           *    keys are the names and the values are the constructors.
12722           * @param {Function} constructor Controller constructor function.
12723           * @description
12724           * See {@link ng.$controllerProvider#register $controllerProvider.register()}.
12725           */
12726          controller: invokeLaterAndSetModuleName('$controllerProvider', 'register'),
12727
12728          /**
12729           * @ngdoc method
12730           * @name angular.Module#directive
12731           * @module ng
12732           * @param {string|Object} name Directive name, or an object map of directives where the
12733           *    keys are the names and the values are the factories.
12734           * @param {Function} directiveFactory Factory function for creating new instance of
12735           * directives.
12736           * @description
12737           * See {@link ng.$compileProvider#directive $compileProvider.directive()}.
12738           */
12739          directive: invokeLaterAndSetModuleName('$compileProvider', 'directive'),
12740
12741          /**
12742           * @ngdoc method
12743           * @name angular.Module#component
12744           * @module ng
12745           * @param {string} name Name of the component in camel-case (i.e. myComp which will match as my-comp)
12746           * @param {Object} options Component definition object (a simplified
12747           *    {@link ng.$compile#directive-definition-object directive definition object})
12748           *
12749           * @description
12750           * See {@link ng.$compileProvider#component $compileProvider.component()}.
12751           */
12752          component: invokeLaterAndSetModuleName('$compileProvider', 'component'),
12753
12754          /**
12755           * @ngdoc method
12756           * @name angular.Module#config
12757           * @module ng
12758           * @param {Function} configFn Execute this function on module load. Useful for service
12759           *    configuration.
12760           * @description
12761           * Use this method to register work which needs to be performed on module loading.
12762           * For more about how to configure services, see
12763           * {@link providers#provider-recipe Provider Recipe}.
12764           */
12765          config: config,
12766
12767          /**
12768           * @ngdoc method
12769           * @name angular.Module#run
12770           * @module ng
12771           * @param {Function} initializationFn Execute this function after injector creation.
12772           *    Useful for application initialization.
vendor: 9,201 bytes, lines 12773-13107
12773           * @description
12774           * Use this method to register work which should be performed when the injector is done
12775           * loading all modules.
12776           */
12777          run: function(block) {
12778            runBlocks.push(block);
12779            return this;
12780          }
12781        };
12782
12783        if (configFn) {
12784          config(configFn);
12785        }
12786
12787        return moduleInstance;
12788
12789        /**
12790         * @param {string} provider
12791         * @param {string} method
12792         * @param {String=} insertMethod
12793         * @returns {angular.Module}
12794         */
12795        function invokeLater(provider, method, insertMethod, queue) {
12796          if (!queue) queue = invokeQueue;
12797          return function() {
12798            queue[insertMethod || 'push']([provider, method, arguments]);
12799            return moduleInstance;
12800          };
12801        }
12802
12803        /**
12804         * @param {string} provider
12805         * @param {string} method
12806         * @returns {angular.Module}
12807         */
12808        function invokeLaterAndSetModuleName(provider, method, queue) {
12809          if (!queue) queue = invokeQueue;
12810          return function(recipeName, factoryFunction) {
12811            if (factoryFunction && isFunction(factoryFunction)) factoryFunction.$$moduleName = name;
12812            queue.push([provider, method, arguments]);
12813            return moduleInstance;
12814          };
12815        }
12816      });
12817    };
12818  });
12819
12820}
12821
12822/* global shallowCopy: true */
12823
12824/**
12825 * Creates a shallow copy of an object, an array or a primitive.
12826 *
12827 * Assumes that there are no proto properties for objects.
12828 */
12829function shallowCopy(src, dst) {
12830  if (isArray(src)) {
12831    dst = dst || [];
12832
12833    for (var i = 0, ii = src.length; i < ii; i++) {
12834      dst[i] = src[i];
12835    }
12836  } else if (isObject(src)) {
12837    dst = dst || {};
12838
12839    for (var key in src) {
12840      if (!(key.charAt(0) === '$' && key.charAt(1) === '$')) {
12841        dst[key] = src[key];
12842      }
12843    }
12844  }
12845
12846  return dst || src;
12847}
12848
12849/* global toDebugString: true */
12850
12851function serializeObject(obj, maxDepth) {
12852  var seen = [];
12853
12854  // There is no direct way to stringify object until reaching a specific depth
12855  // and a very deep object can cause a performance issue, so we copy the object
12856  // based on this specific depth and then stringify it.
12857  if (isValidObjectMaxDepth(maxDepth)) {
12858    obj = copy(obj, null, maxDepth);
12859  }
12860  return JSON.stringify(obj, function(key, val) {
12861    val = toJsonReplacer(key, val);
12862    if (isObject(val)) {
12863
12864      if (seen.indexOf(val) >= 0) return '...';
12865
12866      seen.push(val);
12867    }
12868    return val;
12869  });
12870}
12871
12872function toDebugString(obj, maxDepth) {
12873  if (typeof obj === 'function') {
12874    return obj.toString().replace(/ \{[\s\S]*$/, '');
12875  } else if (isUndefined(obj)) {
12876    return 'undefined';
12877  } else if (typeof obj !== 'string') {
12878    return serializeObject(obj, maxDepth);
12879  }
12880  return obj;
12881}
12882
12883/* global angularModule: true,
12884  version: true,
12885
12886  $CompileProvider,
12887
12888  htmlAnchorDirective,
12889  inputDirective,
12890  inputDirective,
12891  formDirective,
12892  scriptDirective,
12893  selectDirective,
12894  optionDirective,
12895  ngBindDirective,
12896  ngBindHtmlDirective,
12897  ngBindTemplateDirective,
12898  ngClassDirective,
12899  ngClassEvenDirective,
12900  ngClassOddDirective,
12901  ngCloakDirective,
12902  ngControllerDirective,
12903  ngFormDirective,
12904  ngHideDirective,
12905  ngIfDirective,
12906  ngIncludeDirective,
12907  ngIncludeFillContentDirective,
12908  ngInitDirective,
12909  ngNonBindableDirective,
12910  ngPluralizeDirective,
12911  ngRepeatDirective,
12912  ngShowDirective,
12913  ngStyleDirective,
12914  ngSwitchDirective,
12915  ngSwitchWhenDirective,
12916  ngSwitchDefaultDirective,
12917  ngOptionsDirective,
12918  ngTranscludeDirective,
12919  ngModelDirective,
12920  ngListDirective,
12921  ngChangeDirective,
12922  patternDirective,
12923  patternDirective,
12924  requiredDirective,
12925  requiredDirective,
12926  minlengthDirective,
12927  minlengthDirective,
12928  maxlengthDirective,
12929  maxlengthDirective,
12930  ngValueDirective,
12931  ngModelOptionsDirective,
12932  ngAttributeAliasDirectives,
12933  ngEventDirectives,
12934
12935  $AnchorScrollProvider,
12936  $AnimateProvider,
12937  $CoreAnimateCssProvider,
12938  $$CoreAnimateJsProvider,
12939  $$CoreAnimateQueueProvider,
12940  $$AnimateRunnerFactoryProvider,
12941  $$AnimateAsyncRunFactoryProvider,
12942  $BrowserProvider,
12943  $CacheFactoryProvider,
12944  $ControllerProvider,
12945  $DateProvider,
12946  $DocumentProvider,
12947  $$IsDocumentHiddenProvider,
12948  $ExceptionHandlerProvider,
12949  $FilterProvider,
12950  $$ForceReflowProvider,
12951  $InterpolateProvider,
12952  $IntervalProvider,
12953  $HttpProvider,
12954  $HttpParamSerializerProvider,
12955  $HttpParamSerializerJQLikeProvider,
12956  $HttpBackendProvider,
12957  $xhrFactoryProvider,
12958  $jsonpCallbacksProvider,
12959  $LocationProvider,
12960  $LogProvider,
12961  $$MapProvider,
12962  $ParseProvider,
12963  $RootScopeProvider,
12964  $QProvider,
12965  $$QProvider,
12966  $$SanitizeUriProvider,
12967  $SceProvider,
12968  $SceDelegateProvider,
12969  $SnifferProvider,
12970  $TemplateCacheProvider,
12971  $TemplateRequestProvider,
12972  $$TestabilityProvider,
12973  $TimeoutProvider,
12974  $$RAFProvider,
12975  $WindowProvider,
12976  $$jqLiteProvider,
12977  $$CookieReaderProvider
12978*/
12979
12980
12981/**
12982 * @ngdoc object
12983 * @name angular.version
12984 * @module ng
12985 * @description
12986 * An object that contains information about the current AngularJS version.
12987 *
12988 * This object has the following properties:
12989 *
12990 * - `full` – `{string}` – Full version string, such as "0.9.18".
12991 * - `major` – `{number}` – Major version number, such as "0".
12992 * - `minor` – `{number}` – Minor version number, such as "9".
12993 * - `dot` – `{number}` – Dot version number, such as "18".
12994 * - `codeName` – `{string}` – Code name of the release, such as "jiggling-armfat".
12995 */
12996var version = {
12997  // These placeholder strings will be replaced by grunt's `build` task.
12998  // They need to be double- or single-quoted.
12999  full: '1.6.3',
13000  major: 1,
13001  minor: 6,
13002  dot: 3,
13003  codeName: 'scriptalicious-bootstrapping'
13004};
13005
13006
13007function publishExternalAPI(angular) {
13008  extend(angular, {
13009    'errorHandlingConfig': errorHandlingConfig,
13010    'bootstrap': bootstrap,
13011    'copy': copy,
13012    'extend': extend,
13013    'merge': merge,
13014    'equals': equals,
13015    'element': jqLite,
13016    'forEach': forEach,
13017    'injector': createInjector,
13018    'noop': noop,
13019    'bind': bind,
13020    'toJson': toJson,
13021    'fromJson': fromJson,
13022    'identity': identity,
13023    'isUndefined': isUndefined,
13024    'isDefined': isDefined,
13025    'isString': isString,
13026    'isFunction': isFunction,
13027    'isObject': isObject,
13028    'isNumber': isNumber,
13029    'isElement': isElement,
13030    'isArray': isArray,
13031    'version': version,
13032    'isDate': isDate,
13033    'lowercase': lowercase,
13034    'uppercase': uppercase,
13035    'callbacks': {$$counter: 0},
13036    'getTestability': getTestability,
13037    'reloadWithDebugInfo': reloadWithDebugInfo,
13038    '$$minErr': minErr,
13039    '$$csp': csp,
13040    '$$encodeUriSegment': encodeUriSegment,
13041    '$$encodeUriQuery': encodeUriQuery,
13042    '$$stringify': stringify
13043  });
13044
13045  angularModule = setupModuleLoader(window);
13046
13047  angularModule('ng', ['ngLocale'], ['$provide',
13048    function ngModule($provide) {
13049      // $$sanitizeUriProvider needs to be before $compileProvider as it is used by it.
13050      $provide.provider({
13051        $$sanitizeUri: $$SanitizeUriProvider
13052      });
13053      $provide.provider('$compile', $CompileProvider).
13054        directive({
13055            a: htmlAnchorDirective,
13056            input: inputDirective,
13057            textarea: inputDirective,
13058            form: formDirective,
13059            script: scriptDirective,
13060            select: selectDirective,
13061            option: optionDirective,
13062            ngBind: ngBindDirective,
13063            ngBindHtml: ngBindHtmlDirective,
13064            ngBindTemplate: ngBindTemplateDirective,
13065            ngClass: ngClassDirective,
13066            ngClassEven: ngClassEvenDirective,
13067            ngClassOdd: ngClassOddDirective,
13068            ngCloak: ngCloakDirective,
13069            ngController: ngControllerDirective,
13070            ngForm: ngFormDirective,
13071            ngHide: ngHideDirective,
13072            ngIf: ngIfDirective,
13073            ngInclude: ngIncludeDirective,
13074            ngInit: ngInitDirective,
13075            ngNonBindable: ngNonBindableDirective,
13076            ngPluralize: ngPluralizeDirective,
13077            ngRepeat: ngRepeatDirective,
13078            ngShow: ngShowDirective,
13079            ngStyle: ngStyleDirective,
13080            ngSwitch: ngSwitchDirective,
13081            ngSwitchWhen: ngSwitchWhenDirective,
13082            ngSwitchDefault: ngSwitchDefaultDirective,
13083            ngOptions: ngOptionsDirective,
13084            ngTransclude: ngTranscludeDirective,
13085            ngModel: ngModelDirective,
13086            ngList: ngListDirective,
13087            ngChange: ngChangeDirective,
13088            pattern: patternDirective,
13089            ngPattern: patternDirective,
13090            required: requiredDirective,
13091            ngRequired: requiredDirective,
13092            minlength: minlengthDirective,
13093            ngMinlength: minlengthDirective,
13094            maxlength: maxlengthDirective,
13095            ngMaxlength: maxlengthDirective,
13096            ngValue: ngValueDirective,
13097            ngModelOptions: ngModelOptionsDirective
13098        }).
13099        directive({
13100          ngInclude: ngIncludeFillContentDirective
13101        }).
13102        directive(ngAttributeAliasDirectives).
13103        directive(ngEventDirectives);
13104      $provide.provider({
13105        $anchorScroll: $AnchorScrollProvider,
13106        $animate: $AnimateProvider,
13107        $animateCss: $CoreAnimateCssProvider,
13108        $$animateJs: $$CoreAnimateJsProvider,
13109        $$animateQueue: $$CoreAnimateQueueProvider,
13110        $$AnimateRunner: $$AnimateRunnerFactoryProvider,
13111        $$animateAsyncRun: $$AnimateAsyncRunFactoryProvider,
13112        $browser: $BrowserProvider,
13113        $cacheFactory: $CacheFactoryProvider,
13114        $controller: $ControllerProvider,
13115        $document: $DocumentProvider,
13116        $$isDocumentHidden: $$IsDocumentHiddenProvider,
13117        $exceptionHandler: $ExceptionHandlerProvider,
13118        $filter: $FilterProvider,
13119        $$forceReflow: $$ForceReflowProvider,
13120        $interpolate: $InterpolateProvider,
13121        $interval: $IntervalProvider,
13122        $http: $HttpProvider,
13123        $httpParamSerializer: $HttpParamSerializerProvider,
13124        $httpParamSerializerJQLike: $HttpParamSerializerJQLikeProvider,
13125        $httpBackend: $HttpBackendProvider,
13126        $xhrFactory: $xhrFactoryProvider,
13127        $jsonpCallbacks: $jsonpCallbacksProvider,
13128        $location: $LocationProvider,
13129        $log: $LogProvider,
13130        $parse: $ParseProvider,
13131        $rootScope: $RootScopeProvider,
13132        $q: $QProvider,
13133        $$q: $$QProvider,
13134        $sce: $SceProvider,
13135        $sceDelegate: $SceDelegateProvider,
13136        $sniffer: $SnifferProvider,
13137        $templateCache: $TemplateCacheProvider,
13138        $templateRequest: $TemplateRequestProvider,
13139        $$testability: $$TestabilityProvider,
13140        $timeout: $TimeoutProvider,
13141        $window: $WindowProvider,
13142        $$rAF: $$RAFProvider,
13143        $$jqLite: $$jqLiteProvider,
13144        $$Map: $$MapProvider,
13145        $$cookieReader: $$CookieReaderProvider
13146      });
13147    }
13148  ])
13149  .info({ angularVersion: '1.6.3' });
13150}
13151
13152/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
13153 *     Any commits to this file should be reviewed with security in mind.  *
13154 *   Changes to this file can potentially create security vulnerabilities. *
13155 *          An approval from 2 Core members with history of modifying      *
13156 *                         this file is required.                          *
13157 *                                                                         *
13158 *  Does the change somehow allow for arbitrary javascript to be executed? *
13159 *    Or allows for someone to change the prototype of built-in objects?   *
13160 *     Or gives undesired access to variables likes document or window?    *
13161 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
13162
13163/* global
13164  JQLitePrototype: true,
13165  BOOLEAN_ATTR: true,
13166  ALIASED_ATTR: true
13167*/
13168
13169//////////////////////////////////
13170//JQLite
13171//////////////////////////////////
13172
13173/**
13174 * @ngdoc function
13175 * @name angular.element
13176 * @module ng
13177 * @kind function
13178 *
13179 * @description
13180 * Wraps a raw DOM element or HTML string as a [jQuery](http://jquery.com) element.
13181 *
13182 * If jQuery is available, `angular.element` is an alias for the
13183 * [jQuery](http://api.jquery.com/jQuery/) function. If jQuery is not available, `angular.element`
13184 * delegates to Angular's built-in subset of jQuery, called "jQuery lite" or **jqLite**.
13185 *
13186 * jqLite is a tiny, API-compatible subset of jQuery that allows
13187 * Angular to manipulate the DOM in a cross-browser compatible way. jqLite implements only the most
13188 * commonly needed functionality with the goal of having a very small footprint.
13189 *
13190 * To use `jQuery`, simply ensure it is loaded before the `angular.js` file. You can also use the
13191 * {@link ngJq `ngJq`} directive to specify that jqlite should be used over jQuery, or to use a
13192 * specific version of jQuery if multiple versions exist on the page.
13193 *
13194 * <div class="alert alert-info">**Note:** All element references in Angular are always wrapped with jQuery or
13195 * jqLite (such as the element argument in a directive's compile / link function). They are never raw DOM references.</div>
13196 *
13197 * <div class="alert alert-warning">**Note:** Keep in mind that this function will not find elements
13198 * by tag name / CSS selector. For lookups by tag name, try instead `angular.element(document).find(...)`
13199 * or `$document.find()`, or use the standard DOM APIs, e.g. `document.querySelectorAll()`.</div>
13200 *
13201 * ## Angular's jqLite
13202 * jqLite provides only the following jQuery methods:
13203 *
13204 * - [`addClass()`](http://api.jquery.com/addClass/) - Does not support a function as first argument
13205 * - [`after()`](http://api.jquery.com/after/)
13206 * - [`append()`](http://api.jquery.com/append/)
13207 * - [`attr()`](http://api.jquery.com/attr/) - Does not support functions as parameters
13208 * - [`bind()`](http://api.jquery.com/bind/) (_deprecated_, use [`on()`](http://api.jquery.com/on/)) - Does not support namespaces, selectors or eventData
13209 * - [`children()`](http://api.jquery.com/children/) - Does not support selectors
13210 * - [`clone()`](http://api.jquery.com/clone/)
13211 * - [`contents()`](http://api.jquery.com/contents/)
13212 * - [`css()`](http://api.jquery.com/css/) - Only retrieves inline-styles, does not call `getComputedStyle()`.
13213 *   As a setter, does not convert numbers to strings or append 'px', and also does not have automatic property prefixing.
13214 * - [`data()`](http://api.jquery.com/data/)
13215 * - [`detach()`](http://api.jquery.com/detach/)
13216 * - [`empty()`](http://api.jquery.com/empty/)
13217 * - [`eq()`](http://api.jquery.com/eq/)
13218 * - [`find()`](http://api.jquery.com/find/) - Limited to lookups by tag name
13219 * - [`hasClass()`](http://api.jquery.com/hasClass/)
13220 * - [`html()`](http://api.jquery.com/html/)
13221 * - [`next()`](http://api.jquery.com/next/) - Does not support selectors
13222 * - [`on()`](http://api.jquery.com/on/) - Does not support namespaces, selectors or eventData
13223 * - [`off()`](http://api.jquery.com/off/) - Does not support namespaces, selectors or event object as parameter
13224 * - [`one()`](http://api.jquery.com/one/) - Does not support namespaces or selectors
13225 * - [`parent()`](http://api.jquery.com/parent/) - Does not support selectors
13226 * - [`prepend()`](http://api.jquery.com/prepend/)
13227 * - [`prop()`](http://api.jquery.com/prop/)
13228 * - [`ready()`](http://api.jquery.com/ready/) (_deprecated_, use `angular.element(callback)` instead of `angular.element(document).ready(callback)`)
13229 * - [`remove()`](http://api.jquery.com/remove/)
13230 * - [`removeAttr()`](http://api.jquery.com/removeAttr/) - Does not support multiple attributes
13231 * - [`removeClass()`](http://api.jquery.com/removeClass/) - Does not support a function as first argument
13232 * - [`removeData()`](http://api.jquery.com/removeData/)
13233 * - [`replaceWith()`](http://api.jquery.com/replaceWith/)
13234 * - [`text()`](http://api.jquery.com/text/)
13235 * - [`toggleClass()`](http://api.jquery.com/toggleClass/) - Does not support a function as first argument
13236 * - [`triggerHandler()`](http://api.jquery.com/triggerHandler/) - Passes a dummy event object to handlers
13237 * - [`unbind()`](http://api.jquery.com/unbind/) (_deprecated_, use [`off()`](http://api.jquery.com/off/)) - Does not support namespaces or event object as parameter
13238 * - [`val()`](http://api.jquery.com/val/)
13239 * - [`wrap()`](http://api.jquery.com/wrap/)
13240 *
13241 * ## jQuery/jqLite Extras
13242 * Angular also provides the following additional methods and events to both jQuery and jqLite:
13243 *
13244 * ### Events
13245 * - `$destroy` - AngularJS intercepts all jqLite/jQuery's DOM destruction apis and fires this event
13246 *    on all DOM nodes being removed.  This can be used to clean up any 3rd party bindings to the DOM
13247 *    element before it is removed.
13248 *
13249 * ### Methods
13250 * - `controller(name)` - retrieves the controller of the current element or its parent. By default
13251 *   retrieves controller associated with the `ngController` directive. If `name` is provided as
13252 *   camelCase directive name, then the controller for this directive will be retrieved (e.g.
13253 *   `'ngModel'`).
13254 * - `injector()` - retrieves the injector of the current element or its parent.
13255 * - `scope()` - retrieves the {@link ng.$rootScope.Scope scope} of the current
13256 *   element or its parent. Requires {@link guide/production#disabling-debug-data Debug Data} to
13257 *   be enabled.
13258 * - `isolateScope()` - retrieves an isolate {@link ng.$rootScope.Scope scope} if one is attached directly to the
13259 *   current element. This getter should be used only on elements that contain a directive which starts a new isolate
13260 *   scope. Calling `scope()` on this element always returns the original non-isolate scope.
13261 *   Requires {@link guide/production#disabling-debug-data Debug Data} to be enabled.
13262 * - `inheritedData()` - same as `data()`, but walks up the DOM until a value is found or the top
13263 *   parent element is reached.
13264 *
13265 * @knownIssue You cannot spy on `angular.element` if you are using Jasmine version 1.x. See
13266 * https://github.com/angular/angular.js/issues/14251 for more information.
13267 *
13268 * @param {string|DOMElement} element HTML string or DOMElement to be wrapped into jQuery.
13269 * @returns {Object} jQuery object.
13270 */
13271
13272JQLite.expando = 'ng339';
13273
13274var jqCache = JQLite.cache = {},
13275    jqId = 1;
13276
13277/*
13278 * !!! This is an undocumented "private" function !!!
13279 */
13280JQLite._data = function(node) {
13281  //jQuery always returns an object on cache miss
13282  return this.cache[node[this.expando]] || {};
13283};
13284
13285function jqNextId() { return ++jqId; }
13286
13287
13288var DASH_LOWERCASE_REGEXP = /-([a-z])/g;
13289var MS_HACK_REGEXP = /^-ms-/;
13290var MOUSE_EVENT_MAP = { mouseleave: 'mouseout', mouseenter: 'mouseover' };
13291var jqLiteMinErr = minErr('jqLite');
13292
13293/**
13294 * Converts kebab-case to camelCase.
13295 * There is also a special case for the ms prefix starting with a lowercase letter.
13296 * @param name Name to normalize
13297 */
13298function cssKebabToCamel(name) {
13299    return kebabToCamel(name.replace(MS_HACK_REGEXP, 'ms-'));
13300}
13301
13302function fnCamelCaseReplace(all, letter) {
13303  return letter.toUpperCase();
13304}
13305
13306/**
13307 * Converts kebab-case to camelCase.
13308 * @param name Name to normalize
13309 */
13310function kebabToCamel(name) {
13311  return name
13312    .replace(DASH_LOWERCASE_REGEXP, fnCamelCaseReplace);
13313}
13314
13315var SINGLE_TAG_REGEXP = /^<([\w-]+)\s*\/?>(?:<\/\1>|)$/;
vendor: 12,520 bytes, lines 13316-13765
13316var HTML_REGEXP = /<|&#?\w+;/;
13317var TAG_NAME_REGEXP = /<([\w:-]+)/;
13318var XHTML_TAG_REGEXP = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:-]+)[^>]*)\/>/gi;
13319
13320var wrapMap = {
13321  'option': [1, '<select multiple="multiple">', '</select>'],
13322
13323  'thead': [1, '<table>', '</table>'],
13324  'col': [2, '<table><colgroup>', '</colgroup></table>'],
13325  'tr': [2, '<table><tbody>', '</tbody></table>'],
13326  'td': [3, '<table><tbody><tr>', '</tr></tbody></table>'],
13327  '_default': [0, '', '']
13328};
13329
13330wrapMap.optgroup = wrapMap.option;
13331wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
13332wrapMap.th = wrapMap.td;
13333
13334
13335function jqLiteIsTextNode(html) {
13336  return !HTML_REGEXP.test(html);
13337}
13338
13339function jqLiteAcceptsData(node) {
13340  // The window object can accept data but has no nodeType
13341  // Otherwise we are only interested in elements (1) and documents (9)
13342  var nodeType = node.nodeType;
13343  return nodeType === NODE_TYPE_ELEMENT || !nodeType || nodeType === NODE_TYPE_DOCUMENT;
13344}
13345
13346function jqLiteHasData(node) {
13347  for (var key in jqCache[node.ng339]) {
13348    return true;
13349  }
13350  return false;
13351}
13352
13353function jqLiteCleanData(nodes) {
13354  for (var i = 0, ii = nodes.length; i < ii; i++) {
13355    jqLiteRemoveData(nodes[i]);
13356  }
13357}
13358
13359function jqLiteBuildFragment(html, context) {
13360  var tmp, tag, wrap,
13361      fragment = context.createDocumentFragment(),
13362      nodes = [], i;
13363
13364  if (jqLiteIsTextNode(html)) {
13365    // Convert non-html into a text node
13366    nodes.push(context.createTextNode(html));
13367  } else {
13368    // Convert html into DOM nodes
13369    tmp = fragment.appendChild(context.createElement('div'));
13370    tag = (TAG_NAME_REGEXP.exec(html) || ['', ''])[1].toLowerCase();
13371    wrap = wrapMap[tag] || wrapMap._default;
13372    tmp.innerHTML = wrap[1] + html.replace(XHTML_TAG_REGEXP, '<$1></$2>') + wrap[2];
13373
13374    // Descend through wrappers to the right content
13375    i = wrap[0];
13376    while (i--) {
13377      tmp = tmp.lastChild;
13378    }
13379
13380    nodes = concat(nodes, tmp.childNodes);
13381
13382    tmp = fragment.firstChild;
13383    tmp.textContent = '';
13384  }
13385
13386  // Remove wrapper from fragment
13387  fragment.textContent = '';
13388  fragment.innerHTML = ''; // Clear inner HTML
13389  forEach(nodes, function(node) {
13390    fragment.appendChild(node);
13391  });
13392
13393  return fragment;
13394}
13395
13396function jqLiteParseHTML(html, context) {
13397  context = context || window.document;
13398  var parsed;
13399
13400  if ((parsed = SINGLE_TAG_REGEXP.exec(html))) {
13401    return [context.createElement(parsed[1])];
13402  }
13403
13404  if ((parsed = jqLiteBuildFragment(html, context))) {
13405    return parsed.childNodes;
13406  }
13407
13408  return [];
13409}
13410
13411function jqLiteWrapNode(node, wrapper) {
13412  var parent = node.parentNode;
13413
13414  if (parent) {
13415    parent.replaceChild(wrapper, node);
13416  }
13417
13418  wrapper.appendChild(node);
13419}
13420
13421
13422// IE9-11 has no method "contains" in SVG element and in Node.prototype. Bug #10259.
13423var jqLiteContains = window.Node.prototype.contains || /** @this */ function(arg) {
13424  // eslint-disable-next-line no-bitwise
13425  return !!(this.compareDocumentPosition(arg) & 16);
13426};
13427
13428/////////////////////////////////////////////
13429function JQLite(element) {
13430  if (element instanceof JQLite) {
13431    return element;
13432  }
13433
13434  var argIsString;
13435
13436  if (isString(element)) {
13437    element = trim(element);
13438    argIsString = true;
13439  }
13440  if (!(this instanceof JQLite)) {
13441    if (argIsString && element.charAt(0) !== '<') {
13442      throw jqLiteMinErr('nosel', 'Looking up elements via selectors is not supported by jqLite! See: http://docs.angularjs.org/api/angular.element');
13443    }
13444    return new JQLite(element);
13445  }
13446
13447  if (argIsString) {
13448    jqLiteAddNodes(this, jqLiteParseHTML(element));
13449  } else if (isFunction(element)) {
13450    jqLiteReady(element);
13451  } else {
13452    jqLiteAddNodes(this, element);
13453  }
13454}
13455
13456function jqLiteClone(element) {
13457  return element.cloneNode(true);
13458}
13459
13460function jqLiteDealoc(element, onlyDescendants) {
13461  if (!onlyDescendants) jqLiteRemoveData(element);
13462
13463  if (element.querySelectorAll) {
13464    var descendants = element.querySelectorAll('*');
13465    for (var i = 0, l = descendants.length; i < l; i++) {
13466      jqLiteRemoveData(descendants[i]);
13467    }
13468  }
13469}
13470
13471function jqLiteOff(element, type, fn, unsupported) {
13472  if (isDefined(unsupported)) throw jqLiteMinErr('offargs', 'jqLite#off() does not support the `selector` argument');
13473
13474  var expandoStore = jqLiteExpandoStore(element);
13475  var events = expandoStore && expandoStore.events;
13476  var handle = expandoStore && expandoStore.handle;
13477
13478  if (!handle) return; //no listeners registered
13479
13480  if (!type) {
13481    for (type in events) {
13482      if (type !== '$destroy') {
13483        element.removeEventListener(type, handle);
13484      }
13485      delete events[type];
13486    }
13487  } else {
13488
13489    var removeHandler = function(type) {
13490      var listenerFns = events[type];
13491      if (isDefined(fn)) {
13492        arrayRemove(listenerFns || [], fn);
13493      }
13494      if (!(isDefined(fn) && listenerFns && listenerFns.length > 0)) {
13495        element.removeEventListener(type, handle);
13496        delete events[type];
13497      }
13498    };
13499
13500    forEach(type.split(' '), function(type) {
13501      removeHandler(type);
13502      if (MOUSE_EVENT_MAP[type]) {
13503        removeHandler(MOUSE_EVENT_MAP[type]);
13504      }
13505    });
13506  }
13507}
13508
13509function jqLiteRemoveData(element, name) {
13510  var expandoId = element.ng339;
13511  var expandoStore = expandoId && jqCache[expandoId];
13512
13513  if (expandoStore) {
13514    if (name) {
13515      delete expandoStore.data[name];
13516      return;
13517    }
13518
13519    if (expandoStore.handle) {
13520      if (expandoStore.events.$destroy) {
13521        expandoStore.handle({}, '$destroy');
13522      }
13523      jqLiteOff(element);
13524    }
13525    delete jqCache[expandoId];
13526    element.ng339 = undefined; // don't delete DOM expandos. IE and Chrome don't like it
13527  }
13528}
13529
13530
13531function jqLiteExpandoStore(element, createIfNecessary) {
13532  var expandoId = element.ng339,
13533      expandoStore = expandoId && jqCache[expandoId];
13534
13535  if (createIfNecessary && !expandoStore) {
13536    element.ng339 = expandoId = jqNextId();
13537    expandoStore = jqCache[expandoId] = {events: {}, data: {}, handle: undefined};
13538  }
13539
13540  return expandoStore;
13541}
13542
13543
13544function jqLiteData(element, key, value) {
13545  if (jqLiteAcceptsData(element)) {
13546    var prop;
13547
13548    var isSimpleSetter = isDefined(value);
13549    var isSimpleGetter = !isSimpleSetter && key && !isObject(key);
13550    var massGetter = !key;
13551    var expandoStore = jqLiteExpandoStore(element, !isSimpleGetter);
13552    var data = expandoStore && expandoStore.data;
13553
13554    if (isSimpleSetter) { // data('key', value)
13555      data[kebabToCamel(key)] = value;
13556    } else {
13557      if (massGetter) {  // data()
13558        return data;
13559      } else {
13560        if (isSimpleGetter) { // data('key')
13561          // don't force creation of expandoStore if it doesn't exist yet
13562          return data && data[kebabToCamel(key)];
13563        } else { // mass-setter: data({key1: val1, key2: val2})
13564          for (prop in key) {
13565            data[kebabToCamel(prop)] = key[prop];
13566          }
13567        }
13568      }
13569    }
13570  }
13571}
13572
13573function jqLiteHasClass(element, selector) {
13574  if (!element.getAttribute) return false;
13575  return ((' ' + (element.getAttribute('class') || '') + ' ').replace(/[\n\t]/g, ' ').
13576      indexOf(' ' + selector + ' ') > -1);
13577}
13578
13579function jqLiteRemoveClass(element, cssClasses) {
13580  if (cssClasses && element.setAttribute) {
13581    forEach(cssClasses.split(' '), function(cssClass) {
13582      element.setAttribute('class', trim(
13583          (' ' + (element.getAttribute('class') || '') + ' ')
13584          .replace(/[\n\t]/g, ' ')
13585          .replace(' ' + trim(cssClass) + ' ', ' '))
13586      );
13587    });
13588  }
13589}
13590
13591function jqLiteAddClass(element, cssClasses) {
13592  if (cssClasses && element.setAttribute) {
13593    var existingClasses = (' ' + (element.getAttribute('class') || '') + ' ')
13594                            .replace(/[\n\t]/g, ' ');
13595
13596    forEach(cssClasses.split(' '), function(cssClass) {
13597      cssClass = trim(cssClass);
13598      if (existingClasses.indexOf(' ' + cssClass + ' ') === -1) {
13599        existingClasses += cssClass + ' ';
13600      }
13601    });
13602
13603    element.setAttribute('class', trim(existingClasses));
13604  }
13605}
13606
13607
13608function jqLiteAddNodes(root, elements) {
13609  // THIS CODE IS VERY HOT. Don't make changes without benchmarking.
13610
13611  if (elements) {
13612
13613    // if a Node (the most common case)
13614    if (elements.nodeType) {
13615      root[root.length++] = elements;
13616    } else {
13617      var length = elements.length;
13618
13619      // if an Array or NodeList and not a Window
13620      if (typeof length === 'number' && elements.window !== elements) {
13621        if (length) {
13622          for (var i = 0; i < length; i++) {
13623            root[root.length++] = elements[i];
13624          }
13625        }
13626      } else {
13627        root[root.length++] = elements;
13628      }
13629    }
13630  }
13631}
13632
13633
13634function jqLiteController(element, name) {
13635  return jqLiteInheritedData(element, '$' + (name || 'ngController') + 'Controller');
13636}
13637
13638function jqLiteInheritedData(element, name, value) {
13639  // if element is the document object work with the html element instead
13640  // this makes $(document).scope() possible
13641  if (element.nodeType === NODE_TYPE_DOCUMENT) {
13642    element = element.documentElement;
13643  }
13644  var names = isArray(name) ? name : [name];
13645
13646  while (element) {
13647    for (var i = 0, ii = names.length; i < ii; i++) {
13648      if (isDefined(value = jqLite.data(element, names[i]))) return value;
13649    }
13650
13651    // If dealing with a document fragment node with a host element, and no parent, use the host
13652    // element as the parent. This enables directives within a Shadow DOM or polyfilled Shadow DOM
13653    // to lookup parent controllers.
13654    element = element.parentNode || (element.nodeType === NODE_TYPE_DOCUMENT_FRAGMENT && element.host);
13655  }
13656}
13657
13658function jqLiteEmpty(element) {
13659  jqLiteDealoc(element, true);
13660  while (element.firstChild) {
13661    element.removeChild(element.firstChild);
13662  }
13663}
13664
13665function jqLiteRemove(element, keepData) {
13666  if (!keepData) jqLiteDealoc(element);
13667  var parent = element.parentNode;
13668  if (parent) parent.removeChild(element);
13669}
13670
13671
13672function jqLiteDocumentLoaded(action, win) {
13673  win = win || window;
13674  if (win.document.readyState === 'complete') {
13675    // Force the action to be run async for consistent behavior
13676    // from the action's point of view
13677    // i.e. it will definitely not be in a $apply
13678    win.setTimeout(action);
13679  } else {
13680    // No need to unbind this handler as load is only ever called once
13681    jqLite(win).on('load', action);
13682  }
13683}
13684
13685function jqLiteReady(fn) {
13686  function trigger() {
13687    window.document.removeEventListener('DOMContentLoaded', trigger);
13688    window.removeEventListener('load', trigger);
13689    fn();
13690  }
13691
13692  // check if document is already loaded
13693  if (window.document.readyState === 'complete') {
13694    window.setTimeout(fn);
13695  } else {
13696    // We can not use jqLite since we are not done loading and jQuery could be loaded later.
13697
13698    // Works for modern browsers and IE9
13699    window.document.addEventListener('DOMContentLoaded', trigger);
13700
13701    // Fallback to window.onload for others
13702    window.addEventListener('load', trigger);
13703  }
13704}
13705
13706//////////////////////////////////////////
13707// Functions which are declared directly.
13708//////////////////////////////////////////
13709var JQLitePrototype = JQLite.prototype = {
13710  ready: jqLiteReady,
13711  toString: function() {
13712    var value = [];
13713    forEach(this, function(e) { value.push('' + e);});
13714    return '[' + value.join(', ') + ']';
13715  },
13716
13717  eq: function(index) {
13718      return (index >= 0) ? jqLite(this[index]) : jqLite(this[this.length + index]);
13719  },
13720
13721  length: 0,
13722  push: push,
13723  sort: [].sort,
13724  splice: [].splice
13725};
13726
13727//////////////////////////////////////////
13728// Functions iterating getter/setters.
13729// these functions return self on setter and
13730// value on get.
13731//////////////////////////////////////////
13732var BOOLEAN_ATTR = {};
13733forEach('multiple,selected,checked,disabled,readOnly,required,open'.split(','), function(value) {
13734  BOOLEAN_ATTR[lowercase(value)] = value;
13735});
13736var BOOLEAN_ELEMENTS = {};
13737forEach('input,select,option,textarea,button,form,details'.split(','), function(value) {
13738  BOOLEAN_ELEMENTS[value] = true;
13739});
13740var ALIASED_ATTR = {
13741  'ngMinlength': 'minlength',
13742  'ngMaxlength': 'maxlength',
13743  'ngMin': 'min',
13744  'ngMax': 'max',
13745  'ngPattern': 'pattern',
13746  'ngStep': 'step'
13747};
13748
13749function getBooleanAttrName(element, name) {
13750  // check dom last since we will most likely fail on name
13751  var booleanAttr = BOOLEAN_ATTR[name.toLowerCase()];
13752
13753  // booleanAttr is here twice to minimize DOM access
13754  return booleanAttr && BOOLEAN_ELEMENTS[nodeName_(element)] && booleanAttr;
13755}
13756
13757function getAliasedAttrName(name) {
13758  return ALIASED_ATTR[name];
13759}
13760
13761forEach({
13762  data: jqLiteData,
13763  removeData: jqLiteRemoveData,
13764  hasData: jqLiteHasData,
13765  cleanData: jqLiteCleanData
vendor: 15,519 bytes, lines 13765-14306
13765
13766}, function(fn, name) {
13767  JQLite[name] = fn;
13768});
13769
13770forEach({
13771  data: jqLiteData,
13772  inheritedData: jqLiteInheritedData,
13773
13774  scope: function(element) {
13775    // Can't use jqLiteData here directly so we stay compatible with jQuery!
13776    return jqLite.data(element, '$scope') || jqLiteInheritedData(element.parentNode || element, ['$isolateScope', '$scope']);
13777  },
13778
13779  isolateScope: function(element) {
13780    // Can't use jqLiteData here directly so we stay compatible with jQuery!
13781    return jqLite.data(element, '$isolateScope') || jqLite.data(element, '$isolateScopeNoTemplate');
13782  },
13783
13784  controller: jqLiteController,
13785
13786  injector: function(element) {
13787    return jqLiteInheritedData(element, '$injector');
13788  },
13789
13790  removeAttr: function(element, name) {
13791    element.removeAttribute(name);
13792  },
13793
13794  hasClass: jqLiteHasClass,
13795
13796  css: function(element, name, value) {
13797    name = cssKebabToCamel(name);
13798
13799    if (isDefined(value)) {
13800      element.style[name] = value;
13801    } else {
13802      return element.style[name];
13803    }
13804  },
13805
13806  attr: function(element, name, value) {
13807    var ret;
13808    var nodeType = element.nodeType;
13809    if (nodeType === NODE_TYPE_TEXT || nodeType === NODE_TYPE_ATTRIBUTE || nodeType === NODE_TYPE_COMMENT ||
13810      !element.getAttribute) {
13811      return;
13812    }
13813
13814    var lowercasedName = lowercase(name);
13815    var isBooleanAttr = BOOLEAN_ATTR[lowercasedName];
13816
13817    if (isDefined(value)) {
13818      // setter
13819
13820      if (value === null || (value === false && isBooleanAttr)) {
13821        element.removeAttribute(name);
13822      } else {
13823        element.setAttribute(name, isBooleanAttr ? lowercasedName : value);
13824      }
13825    } else {
13826      // getter
13827
13828      ret = element.getAttribute(name);
13829
13830      if (isBooleanAttr && ret !== null) {
13831        ret = lowercasedName;
13832      }
13833      // Normalize non-existing attributes to undefined (as jQuery).
13834      return ret === null ? undefined : ret;
13835    }
13836  },
13837
13838  prop: function(element, name, value) {
13839    if (isDefined(value)) {
13840      element[name] = value;
13841    } else {
13842      return element[name];
13843    }
13844  },
13845
13846  text: (function() {
13847    getText.$dv = '';
13848    return getText;
13849
13850    function getText(element, value) {
13851      if (isUndefined(value)) {
13852        var nodeType = element.nodeType;
13853        return (nodeType === NODE_TYPE_ELEMENT || nodeType === NODE_TYPE_TEXT) ? element.textContent : '';
13854      }
13855      element.textContent = value;
13856    }
13857  })(),
13858
13859  val: function(element, value) {
13860    if (isUndefined(value)) {
13861      if (element.multiple && nodeName_(element) === 'select') {
13862        var result = [];
13863        forEach(element.options, function(option) {
13864          if (option.selected) {
13865            result.push(option.value || option.text);
13866          }
13867        });
13868        return result;
13869      }
13870      return element.value;
13871    }
13872    element.value = value;
13873  },
13874
13875  html: function(element, value) {
13876    if (isUndefined(value)) {
13877      return element.innerHTML;
13878    }
13879    jqLiteDealoc(element, true);
13880    element.innerHTML = value;
13881  },
13882
13883  empty: jqLiteEmpty
13884}, function(fn, name) {
13885  /**
13886   * Properties: writes return selection, reads return first value
13887   */
13888  JQLite.prototype[name] = function(arg1, arg2) {
13889    var i, key;
13890    var nodeCount = this.length;
13891
13892    // jqLiteHasClass has only two arguments, but is a getter-only fn, so we need to special-case it
13893    // in a way that survives minification.
13894    // jqLiteEmpty takes no arguments but is a setter.
13895    if (fn !== jqLiteEmpty &&
13896        (isUndefined((fn.length === 2 && (fn !== jqLiteHasClass && fn !== jqLiteController)) ? arg1 : arg2))) {
13897      if (isObject(arg1)) {
13898
13899        // we are a write, but the object properties are the key/values
13900        for (i = 0; i < nodeCount; i++) {
13901          if (fn === jqLiteData) {
13902            // data() takes the whole object in jQuery
13903            fn(this[i], arg1);
13904          } else {
13905            for (key in arg1) {
13906              fn(this[i], key, arg1[key]);
13907            }
13908          }
13909        }
13910        // return self for chaining
13911        return this;
13912      } else {
13913        // we are a read, so read the first child.
13914        // TODO: do we still need this?
13915        var value = fn.$dv;
13916        // Only if we have $dv do we iterate over all, otherwise it is just the first element.
13917        var jj = (isUndefined(value)) ? Math.min(nodeCount, 1) : nodeCount;
13918        for (var j = 0; j < jj; j++) {
13919          var nodeValue = fn(this[j], arg1, arg2);
13920          value = value ? value + nodeValue : nodeValue;
13921        }
13922        return value;
13923      }
13924    } else {
13925      // we are a write, so apply to all children
13926      for (i = 0; i < nodeCount; i++) {
13927        fn(this[i], arg1, arg2);
13928      }
13929      // return self for chaining
13930      return this;
13931    }
13932  };
13933});
13934
13935function createEventHandler(element, events) {
13936  var eventHandler = function(event, type) {
13937    // jQuery specific api
13938    event.isDefaultPrevented = function() {
13939      return event.defaultPrevented;
13940    };
13941
13942    var eventFns = events[type || event.type];
13943    var eventFnsLength = eventFns ? eventFns.length : 0;
13944
13945    if (!eventFnsLength) return;
13946
13947    if (isUndefined(event.immediatePropagationStopped)) {
13948      var originalStopImmediatePropagation = event.stopImmediatePropagation;
13949      event.stopImmediatePropagation = function() {
13950        event.immediatePropagationStopped = true;
13951
13952        if (event.stopPropagation) {
13953          event.stopPropagation();
13954        }
13955
13956        if (originalStopImmediatePropagation) {
13957          originalStopImmediatePropagation.call(event);
13958        }
13959      };
13960    }
13961
13962    event.isImmediatePropagationStopped = function() {
13963      return event.immediatePropagationStopped === true;
13964    };
13965
13966    // Some events have special handlers that wrap the real handler
13967    var handlerWrapper = eventFns.specialHandlerWrapper || defaultHandlerWrapper;
13968
13969    // Copy event handlers in case event handlers array is modified during execution.
13970    if ((eventFnsLength > 1)) {
13971      eventFns = shallowCopy(eventFns);
13972    }
13973
13974    for (var i = 0; i < eventFnsLength; i++) {
13975      if (!event.isImmediatePropagationStopped()) {
13976        handlerWrapper(element, event, eventFns[i]);
13977      }
13978    }
13979  };
13980
13981  // TODO: this is a hack for angularMocks/clearDataCache that makes it possible to deregister all
13982  //       events on `element`
13983  eventHandler.elem = element;
13984  return eventHandler;
13985}
13986
13987function defaultHandlerWrapper(element, event, handler) {
13988  handler.call(element, event);
13989}
13990
13991function specialMouseHandlerWrapper(target, event, handler) {
13992  // Refer to jQuery's implementation of mouseenter & mouseleave
13993  // Read about mouseenter and mouseleave:
13994  // http://www.quirksmode.org/js/events_mouse.html#link8
13995  var related = event.relatedTarget;
13996  // For mousenter/leave call the handler if related is outside the target.
13997  // NB: No relatedTarget if the mouse left/entered the browser window
13998  if (!related || (related !== target && !jqLiteContains.call(target, related))) {
13999    handler.call(target, event);
14000  }
14001}
14002
14003//////////////////////////////////////////
14004// Functions iterating traversal.
14005// These functions chain results into a single
14006// selector.
14007//////////////////////////////////////////
14008forEach({
14009  removeData: jqLiteRemoveData,
14010
14011  on: function jqLiteOn(element, type, fn, unsupported) {
14012    if (isDefined(unsupported)) throw jqLiteMinErr('onargs', 'jqLite#on() does not support the `selector` or `eventData` parameters');
14013
14014    // Do not add event handlers to non-elements because they will not be cleaned up.
14015    if (!jqLiteAcceptsData(element)) {
14016      return;
14017    }
14018
14019    var expandoStore = jqLiteExpandoStore(element, true);
14020    var events = expandoStore.events;
14021    var handle = expandoStore.handle;
14022
14023    if (!handle) {
14024      handle = expandoStore.handle = createEventHandler(element, events);
14025    }
14026
14027    // http://jsperf.com/string-indexof-vs-split
14028    var types = type.indexOf(' ') >= 0 ? type.split(' ') : [type];
14029    var i = types.length;
14030
14031    var addHandler = function(type, specialHandlerWrapper, noEventListener) {
14032      var eventFns = events[type];
14033
14034      if (!eventFns) {
14035        eventFns = events[type] = [];
14036        eventFns.specialHandlerWrapper = specialHandlerWrapper;
14037        if (type !== '$destroy' && !noEventListener) {
14038          element.addEventListener(type, handle);
14039        }
14040      }
14041
14042      eventFns.push(fn);
14043    };
14044
14045    while (i--) {
14046      type = types[i];
14047      if (MOUSE_EVENT_MAP[type]) {
14048        addHandler(MOUSE_EVENT_MAP[type], specialMouseHandlerWrapper);
14049        addHandler(type, undefined, true);
14050      } else {
14051        addHandler(type);
14052      }
14053    }
14054  },
14055
14056  off: jqLiteOff,
14057
14058  one: function(element, type, fn) {
14059    element = jqLite(element);
14060
14061    //add the listener twice so that when it is called
14062    //you can remove the original function and still be
14063    //able to call element.off(ev, fn) normally
14064    element.on(type, function onFn() {
14065      element.off(type, fn);
14066      element.off(type, onFn);
14067    });
14068    element.on(type, fn);
14069  },
14070
14071  replaceWith: function(element, replaceNode) {
14072    var index, parent = element.parentNode;
14073    jqLiteDealoc(element);
14074    forEach(new JQLite(replaceNode), function(node) {
14075      if (index) {
14076        parent.insertBefore(node, index.nextSibling);
14077      } else {
14078        parent.replaceChild(node, element);
14079      }
14080      index = node;
14081    });
14082  },
14083
14084  children: function(element) {
14085    var children = [];
14086    forEach(element.childNodes, function(element) {
14087      if (element.nodeType === NODE_TYPE_ELEMENT) {
14088        children.push(element);
14089      }
14090    });
14091    return children;
14092  },
14093
14094  contents: function(element) {
14095    return element.contentDocument || element.childNodes || [];
14096  },
14097
14098  append: function(element, node) {
14099    var nodeType = element.nodeType;
14100    if (nodeType !== NODE_TYPE_ELEMENT && nodeType !== NODE_TYPE_DOCUMENT_FRAGMENT) return;
14101
14102    node = new JQLite(node);
14103
14104    for (var i = 0, ii = node.length; i < ii; i++) {
14105      var child = node[i];
14106      element.appendChild(child);
14107    }
14108  },
14109
14110  prepend: function(element, node) {
14111    if (element.nodeType === NODE_TYPE_ELEMENT) {
14112      var index = element.firstChild;
14113      forEach(new JQLite(node), function(child) {
14114        element.insertBefore(child, index);
14115      });
14116    }
14117  },
14118
14119  wrap: function(element, wrapNode) {
14120    jqLiteWrapNode(element, jqLite(wrapNode).eq(0).clone()[0]);
14121  },
14122
14123  remove: jqLiteRemove,
14124
14125  detach: function(element) {
14126    jqLiteRemove(element, true);
14127  },
14128
14129  after: function(element, newElement) {
14130    var index = element, parent = element.parentNode;
14131
14132    if (parent) {
14133      newElement = new JQLite(newElement);
14134
14135      for (var i = 0, ii = newElement.length; i < ii; i++) {
14136        var node = newElement[i];
14137        parent.insertBefore(node, index.nextSibling);
14138        index = node;
14139      }
14140    }
14141  },
14142
14143  addClass: jqLiteAddClass,
14144  removeClass: jqLiteRemoveClass,
14145
14146  toggleClass: function(element, selector, condition) {
14147    if (selector) {
14148      forEach(selector.split(' '), function(className) {
14149        var classCondition = condition;
14150        if (isUndefined(classCondition)) {
14151          classCondition = !jqLiteHasClass(element, className);
14152        }
14153        (classCondition ? jqLiteAddClass : jqLiteRemoveClass)(element, className);
14154      });
14155    }
14156  },
14157
14158  parent: function(element) {
14159    var parent = element.parentNode;
14160    return parent && parent.nodeType !== NODE_TYPE_DOCUMENT_FRAGMENT ? parent : null;
14161  },
14162
14163  next: function(element) {
14164    return element.nextElementSibling;
14165  },
14166
14167  find: function(element, selector) {
14168    if (element.getElementsByTagName) {
14169      return element.getElementsByTagName(selector);
14170    } else {
14171      return [];
14172    }
14173  },
14174
14175  clone: jqLiteClone,
14176
14177  triggerHandler: function(element, event, extraParameters) {
14178
14179    var dummyEvent, eventFnsCopy, handlerArgs;
14180    var eventName = event.type || event;
14181    var expandoStore = jqLiteExpandoStore(element);
14182    var events = expandoStore && expandoStore.events;
14183    var eventFns = events && events[eventName];
14184
14185    if (eventFns) {
14186      // Create a dummy event to pass to the handlers
14187      dummyEvent = {
14188        preventDefault: function() { this.defaultPrevented = true; },
14189        isDefaultPrevented: function() { return this.defaultPrevented === true; },
14190        stopImmediatePropagation: function() { this.immediatePropagationStopped = true; },
14191        isImmediatePropagationStopped: function() { return this.immediatePropagationStopped === true; },
14192        stopPropagation: noop,
14193        type: eventName,
14194        target: element
14195      };
14196
14197      // If a custom event was provided then extend our dummy event with it
14198      if (event.type) {
14199        dummyEvent = extend(dummyEvent, event);
14200      }
14201
14202      // Copy event handlers in case event handlers array is modified during execution.
14203      eventFnsCopy = shallowCopy(eventFns);
14204      handlerArgs = extraParameters ? [dummyEvent].concat(extraParameters) : [dummyEvent];
14205
14206      forEach(eventFnsCopy, function(fn) {
14207        if (!dummyEvent.isImmediatePropagationStopped()) {
14208          fn.apply(element, handlerArgs);
14209        }
14210      });
14211    }
14212  }
14213}, function(fn, name) {
14214  /**
14215   * chaining functions
14216   */
14217  JQLite.prototype[name] = function(arg1, arg2, arg3) {
14218    var value;
14219
14220    for (var i = 0, ii = this.length; i < ii; i++) {
14221      if (isUndefined(value)) {
14222        value = fn(this[i], arg1, arg2, arg3);
14223        if (isDefined(value)) {
14224          // any function which returns a value needs to be wrapped
14225          value = jqLite(value);
14226        }
14227      } else {
14228        jqLiteAddNodes(value, fn(this[i], arg1, arg2, arg3));
14229      }
14230    }
14231    return isDefined(value) ? value : this;
14232  };
14233});
14234
14235// bind legacy bind/unbind to on/off
14236JQLite.prototype.bind = JQLite.prototype.on;
14237JQLite.prototype.unbind = JQLite.prototype.off;
14238
14239
14240// Provider for private $$jqLite service
14241/** @this */
14242function $$jqLiteProvider() {
14243  this.$get = function $$jqLite() {
14244    return extend(JQLite, {
14245      hasClass: function(node, classes) {
14246        if (node.attr) node = node[0];
14247        return jqLiteHasClass(node, classes);
14248      },
14249      addClass: function(node, classes) {
14250        if (node.attr) node = node[0];
14251        return jqLiteAddClass(node, classes);
14252      },
14253      removeClass: function(node, classes) {
14254        if (node.attr) node = node[0];
14255        return jqLiteRemoveClass(node, classes);
14256      }
14257    });
14258  };
14259}
14260
14261/**
14262 * Computes a hash of an 'obj'.
14263 * Hash of a:
14264 *  string is string
14265 *  number is number as string
14266 *  object is either result of calling $$hashKey function on the object or uniquely generated id,
14267 *         that is also assigned to the $$hashKey property of the object.
14268 *
14269 * @param obj
14270 * @returns {string} hash string such that the same input will have the same hash string.
14271 *         The resulting string key is in 'type:hashKey' format.
14272 */
14273function hashKey(obj, nextUidFn) {
14274  var key = obj && obj.$$hashKey;
14275
14276  if (key) {
14277    if (typeof key === 'function') {
14278      key = obj.$$hashKey();
14279    }
14280    return key;
14281  }
14282
14283  var objType = typeof obj;
14284  if (objType === 'function' || (objType === 'object' && obj !== null)) {
14285    key = obj.$$hashKey = objType + ':' + (nextUidFn || nextUid)();
14286  } else {
14287    key = objType + ':' + obj;
14288  }
14289
14290  return key;
14291}
14292
14293// A minimal ES2015 Map implementation.
14294// Should be bug/feature equivalent to the native implementations of supported browsers
14295// (for the features required in Angular).
14296// See https://kangax.github.io/compat-table/es6/#test-Map
14297var nanKey = Object.create(null);
14298function NgMapShim() {
14299  this._keys = [];
14300  this._values = [];
14301  this._lastKey = NaN;
14302  this._lastIndex = -1;
14303}
14304NgMapShim.prototype = {
14305  _idx: function(key) {
14306    if (key 
vendor: 1,720 bytes, lines 14306-14370
14306=== this._lastKey) {
14307      return this._lastIndex;
14308    }
14309    this._lastKey = key;
14310    this._lastIndex = this._keys.indexOf(key);
14311    return this._lastIndex;
14312  },
14313  _transformKey: function(key) {
14314    return isNumberNaN(key) ? nanKey : key;
14315  },
14316  get: function(key) {
14317    key = this._transformKey(key);
14318    var idx = this._idx(key);
14319    if (idx !== -1) {
14320      return this._values[idx];
14321    }
14322  },
14323  set: function(key, value) {
14324    key = this._transformKey(key);
14325    var idx = this._idx(key);
14326    if (idx === -1) {
14327      idx = this._lastIndex = this._keys.length;
14328    }
14329    this._keys[idx] = key;
14330    this._values[idx] = value;
14331
14332    // Support: IE11
14333    // Do not `return this` to simulate the partial IE11 implementation
14334  },
14335  delete: function(key) {
14336    key = this._transformKey(key);
14337    var idx = this._idx(key);
14338    if (idx === -1) {
14339      return false;
14340    }
14341    this._keys.splice(idx, 1);
14342    this._values.splice(idx, 1);
14343    this._lastKey = NaN;
14344    this._lastIndex = -1;
14345    return true;
14346  }
14347};
14348
14349// For now, always use `NgMapShim`, even if `window.Map` is available. Some native implementations
14350// are still buggy (often in subtle ways) and can cause hard-to-debug failures. When native `Map`
14351// implementations get more stable, we can reconsider switching to `window.Map` (when available).
14352var NgMap = NgMapShim;
14353
14354var $$MapProvider = [/** @this */function() {
14355  this.$get = [function() {
14356    return NgMap;
14357  }];
14358}];
14359
14360/**
14361 * @ngdoc function
14362 * @module ng
14363 * @name angular.injector
14364 * @kind function
14365 *
14366 * @description
14367 * Creates an injector object that can be used for retrieving services as well as for
14368 * dependency injection (see {@link guide/di dependency injection}).
14369 *
14370 * @param {Array.<string|Function>}
14370 modules A list of module functions or their aliases. See
14371 *     {@link angular.module}. The `ng` module must be explicitly added.
14372 * @param {boolean=} [strictDi=false] Whether the injector should be in strict mode, which
14373 *     disallows argument name annotation inference.
14374 * @returns {injector} Injector object. See {@link auto.$injector $injector}.
14375 *
14376 * @example
14377 * Typical usage
14378 * ```js
14379 *   // create an injector
14380 *   var $injector = angular.injector(['ng']);
14381 *
14382 *   // use the injector to kick off your application
14383 *   // use the type inference to auto inject arguments, or use implicit injection
14384 *   $injector.invoke(function($rootScope, $compile, $document) {
14385 *     $compile($document)($rootScope);
14386 *     $rootScope.$digest();
14387 *   });
14388 * ```
14389 *
14390 * Sometimes you want to get access to the injector of a currently running Angular app
14391 * from outside Angular. Perhaps, you want to inject and compile some markup after the
14392 * application has been bootstrapped. You can do this using the extra `injector()` added
14393 * to JQuery/jqLite elements. See {@link angular.element}.
14394 *
14395 * *This is fairly rare but could be the case if a third party library is injecting the
14396 * markup.*
14397 *
14398 * In the following example a new block of HTML containing a `ng-controller`
14399 * directive is added to the end of the document body by JQuery. We then compile and link
14400 * it into the current AngularJS scope.
14401 *
14402 * ```js
14403 * var $div = $('<div ng-controller="MyCtrl">{{content.label}}</div>');
14404 * $(document.body).append($div);
14405 *
14406 * angular.element(document).injector().invoke(function($compile) {
14407 *   var scope = angular.element($div).scope();
14408 *   $compile($div)(scope);
14409 * });
14410 * ```
14411 */
14412
14413
14414/**
14415 * @ngdoc module
14416 * @name auto
14417 * @installation
14418 * @description
14419 *
14420 * Implicit module which gets automatically added to each {@link auto.$injector $injector}.
14421 */
14422
14423var ARROW_ARG = /^([^(]+?)=>/;
14424var FN_ARGS = /^[^(]*\(\s*([^)]*)\)/m;
14425var FN_ARG_SPLIT = /,/;
14426var FN_ARG = /^\s*(_?)(\S+?)\1\s*$/;
14427var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;
14428var $injectorMinErr = minErr('$injector');
14429
14430function stringifyFn(fn) {
14431  return Function.prototype.toString.call(fn);
14432}
14433
14434function extractArgs(fn) {
14435  var fnText = stringifyFn(fn).replace(STRIP_COMMENTS, ''),
14436      args = fnText.match(ARROW_ARG) || fnText.match(FN_ARGS);
14437  return args;
14438}
14439
14440function anonFn(fn) {
14441  // For anonymous functions, showing at the very least the function signature can help in
14442  // debugging.
14443  var args = extractArgs(fn);
14444  if (args) {
14445    return 'function(' + (args[1] || '').replace(/[\s\r\n]+/, ' ') + ')';
14446  }
14447  return 'fn';
14448}
14449
14450function annotate(fn, strictDi, name) {
14451  var $inject,
14452      argDecl,
14453      last;
14454
14455  if (typeof fn === 'function') {
14456    if (!($inject = fn.$inject)) {
14457      $inject = [];
14458      if (fn.length) {
14459        if (strictDi) {
14460          if (!isString(name) || !name) {
14461            name = fn.name || anonFn(fn);
14462          }
14463          throw $injectorMinErr('strictdi',
14464            '{0} is not using explicit annotation and cannot be invoked in strict mode', name);
14465        }
14466        argDecl = extractArgs(fn);
14467        forEach(argDecl[1].split(FN_ARG_SPLIT), function(arg) {
14468          arg.replace(FN_ARG, function(all, underscore, name) {
14469            $inject.push(name);
14470          });
14471        });
14472      }
14473      fn.$inject = $inject;
14474    }
14475  } else if (isArray(fn)) {
14476    last = fn.length - 1;
14477    assertArgFn(fn[last], 'fn');
14478    $inject = fn.slice(0, last);
14479  } else {
14480    assertArgFn(fn, 'fn', true);
14481  }
14482  return $inject;
14483}
14484
14485///////////////////////////////////////
14486
14487/**
14488 * @ngdoc service
14489 * @name $injector
14490 *
14491 * @description
14492 *
14493 * `$injector` is used to retrieve object instances as defined by
14494 * {@link auto.$provide provider}, instantiate types, invoke methods,
14495 * and load modules.
14496 *
14497 * The following always holds true:
14498 *
14499 * ```js
14500 *   var $injector = angular.injector();
14501 *   expect($injector.get('$injector')).toBe($injector);
14502 *   expect($injector.invoke(function($injector) {
14503 *     return $injector;
14504 *   })).toBe($injector);
14505 * ```
14506 *
14507 * # Injection Function Annotation
14508 *
14509 * JavaScript does not have annotations, and annotations are needed for dependency injection. The
14510 * following are all valid ways of annotating function with injection arguments and are equivalent.
14511 *
14512 * ```js
14513 *   // inferred (only works if code not minified/obfuscated)
14514 *   $injector.invoke(function(serviceA){});
14515 *
14516 *   // annotated
14517 *   function explicit(serviceA) {};
14518 *   explicit.$inject = ['serviceA'];
14519 *   $injector.invoke(explicit);
14520 *
14521 *   // inline
14522 *   $injector.invoke(['serviceA', function(serviceA){}]);
14523 * ```
14524 *
14525 * ## Inference
14526 *
14527 * In JavaScript calling `toString()` on a function returns the function definition. The definition
14528 * can then be parsed and the function arguments can be extracted. This method of discovering
14529 * annotations is disallowed when the injector is in strict mode.
14530 * *NOTE:* This does not work with minification, and obfuscation tools since these tools change the
14531 * argument names.
14532 *
14533 * ## `$inject` Annotation
14534 * By adding an `$inject` property onto a function the injection parameters can be specified.
14535 *
14536 * ## Inline
14537 * As an array of injection names, where the last item in the array is the function to call.
14538 */
14539
14540/**
14541 * @ngdoc property
14542 * @name $injector#modules
14543 * @type {Object}
14544 * @description
14545 * A hash containing all the modules that have been loaded into the
14546 * $injector.
14547 *
14548 * You can use this property to find out information about a module via the
14549 * {@link angular.Module#info `myModule.info(...)`} method.
14550 *
14551 * For example:
14552 *
14553 * ```
14554 * var info = $injector.modules['ngAnimate'].info();
14555 * ```
14556 *
14557 * **Do not use this property to attempt to modify the modules after the application
14558 * has been bootstrapped.**
14559 */
14560
14561
14562/**
14563 * @ngdoc method
14564 * @name $injector#get
14565 *
14566 * @description
14567 * Return an instance of the service.
14568 *
14569 * @param {string} name The name of the instance to retrieve.
14570 * @param {string=} caller An optional string to provide the origin of the function call for error messages.
14571 * @return {*} The instance.
14572 */
14573
14574/**
14575 * @ngdoc method
14576 * @name $injector#invoke
14577 *
14578 * @description
14579 * Invoke the method and supply the method arguments from the `$injector`.
14580 *
14581 * @param {Function|Array.<string|Function>} fn The injectable function to invoke. Function parameters are
14582 *   injected according to the {@link guide/di $inject Annotation} rules.
14583 * @param {Object=} self The `this` for the invoked method.
14584 * @param {Object=} locals Optional object. If preset then any argument names are read from this
14585 *                         object first, before the `$injector` is consulted.
14586 * @returns {*} the value returned by the invoked `fn` function.
14587 */
14588
14589/**
14590 * @ngdoc method
14591 * @name $injector#has
14592 *
14593 * @description
14594 * Allows the user to query if the particular service exists.
14595 *
14596 * @param {string} name Name of the service to query.
14597 * @returns {boolean} `true` if injector has given service.
14598 */
14599
14600/**
14601 * @ngdoc method
14602 * @name $injector#instantiate
14603 * @description
14604 * Create a new instance of JS type. The method takes a constructor function, invokes the new
14605 * operator, and supplies all of the arguments to the constructor function as specified by the
14606 * constructor annotation.
14607 *
14608 * @param {Function} Type Annotated constructor function.
14609 * @param {Object=} locals Optional object. If preset then any argument names are read from this
14610 * object first, before the `$injector` is consulted.
14611 * @returns {Object} new instance of `Type`.
14612 */
14613
14614/**
14615 * @ngdoc method
14616 * @name $injector#annotate
14617 *
14618 * @description
14619 * Returns an array of service names which the function is requesting for injection. This API is
14620 * used by the injector to determine which services need to be injected into the function when the
14621 * function is invoked. There are three ways in which the function can be annotated with the needed
14622 * dependencies.
14623 *
14624 * # Argument names
14625 *
14626 * The simplest form is to extract the dependencies from the arguments of the function. This is done
14627 * by converting the function into a string using `toString()` method and extracting the argument
14628 * names.
14629 * ```js
14630 *   // Given
14631 *   function MyController($scope, $route) {
14632 *     // ...
14633 *   }
14634 *
14635 *   // Then
14636 *   expect(injector.annotate(MyController)).toEqual(['$scope', '$route']);
14637 * ```
14638 *
14639 * You can disallow this method by using strict injection mode.
14640 *
14641 * This method does not work with code minification / obfuscation. For this reason the following
14642 * annotation strategies are supported.
14643 *
14644 * # The `$inject` property
14645 *
14646 * If a function has an `$inject` property and its value is an array of strings, then the strings
14647 * represent names of services to be injected into the function.
14648 * ```js
14649 *   // Given
14650 *   var MyController = function(obfuscatedScope, obfuscatedRoute) {
14651 *     // ...
14652 *   }
14653 *   // Define function dependencies
14654 *   MyController['$inject'] = ['$scope', '$route'];
14655 *
14656 *   // Then
14657 *   expect(injector.annotate(MyController)).toEqual(['$scope', '$route']);
14658 * ```
14659 *
14660 * # The array notation
14661 *
14662 * It is often desirable to inline Injected functions and that's when setting the `$inject` property
14663 * is very inconvenient. In these situations using the array notation to specify the dependencies in
14664 * a way that survives minification is a better choice:
14665 *
14666 * ```js
14667 *   // We wish to write this (not minification / obfuscation safe)
14668 *   injector.invoke(function($compile, $rootScope) {
14669 *     // ...
14670 *   });
14671 *
14672 *   // We are forced to write break inlining
14673 *   var tmpFn = function(obfuscatedCompile, obfuscatedRootScope) {
14674 *     // ...
14675 *   };
14676 *   tmpFn.$inject = ['$compile', '$rootScope'];
14677 *   injector.invoke(tmpFn);
14678 *
14679 *   // To better support inline function the inline annotation is supported
14680 *   injector.invoke(['$compile', '$rootScope', function(obfCompile, obfRootScope) {
14681 *     // ...
14682 *   }]);
14683 *
14684 *   // Therefore
14685 *   expect(injector.annotate(
14686 *      ['$compile', '$rootScope', function(obfus_$compile, obfus_$rootScope) {}])
14687 *    ).toEqual(['$compile', '$rootScope']);
14688 * ```
14689 *
14690 * @param {Function|Array.<string|Function>} fn Function for which dependent service names need to
14691 * be retrieved as described above.
14692 *
14693 * @param {boolean=} [strictDi=false] Disallow argument name annotation inference.
14694 *
14695 * @returns {Array.<string>} The names of the services which the function requires.
14696 */
14697
14698
14699
14700/**
14701 * @ngdoc service
14702 * @name $provide
14703 *
14704 * @description
14705 *
14706 * The {@link auto.$provide $provide} service has a number of methods for registering components
14707 * with the {@link auto.$injector $injector}. Many of these functions are also exposed on
14708 * {@link angular.Module}.
14709 *
14710 * An Angular **service** is a singleton object created by a **service factory**.  These **service
14711 * factories** are functions which, in turn, are created by a **service provider**.
14712 * The **service providers** are constructor functions. When instantiated they must contain a
14713 * property called `$get`, which holds the **service factory** function.
14714 *
14715 * When you request a service, the {@link auto.$injector $injector} is responsible for finding the
14716 * correct **service provider**, instantiating it and then calling its `$get` **service factory**
14717 * function to get the instance of the **service**.
14718 *
14719 * Often services have no configuration options and there is no need to add methods to the service
14720 * provider.  The provider will be no more than a constructor function with a `$get` property. For
14721 * these cases the {@link auto.$provide $provide} service has additional helper methods to register
14722 * services without specifying a provider.
14723 *
14724 * * {@link auto.$provide#provider provider(name, provider)} - registers a **service provider** with the
14725 *     {@link auto.$injector $injector}
14726 * * {@link auto.$provide#constant constant(name, obj)} - registers a value/object that can be accessed by
14727 *     providers and services.
14728 * * {@link auto.$provide#value value(name, obj)} - registers a value/object that can only be accessed by
14729 *     services, not providers.
14730 * * {@link auto.$provide#factory factory(name, fn)} - registers a service **factory function**
14731 *     that will be wrapped in a **service provider** object, whose `$get` property will contain the
14732 *     given factory function.
14733 * * {@link auto.$provide#service service(name, Fn)} - registers a **constructor function**
14734 *     that will be wrapped in a **service provider** object, whose `$get` property will instantiate
14735 *      a new object using the given constructor function.
14736 * * {@link auto.$provide#decorator decorator(name, decorFn)} - registers a **decorator function** that
14737 *      will be able to modify or replace the implementation of another service.
14738 *
14739 * See the individual methods for more information and examples.
14740 */
14741
14742/**
14743 * @ngdoc method
14744 * @name $provide#provider
14745 * @description
14746 *
14747 * Register a **provider function** with the {@link auto.$injector $injector}. Provider functions
14748 * are constructor functions, whose instances are responsible for "providing" a factory for a
14749 * service.
14750 *
14751 * Service provider names start with the name of the service they provide followed by `Provider`.
14752 * For example, the {@link ng.$log $log} service has a provider called
14753 * {@link ng.$logProvider $logProvider}.
14754 *
14755 * Service provider objects can have additional methods which allow configuration of the provider
14756 * and its service. Importantly, you can configure what kind of service is created by the `$get`
14757 * method, or how that service will act. For example, the {@link ng.$logProvider $logProvider} has a
14758 * method {@link ng.$logProvider#debugEnabled debugEnabled}
14759 * which lets you specify whether the {@link ng.$log $log} service will log debug messages to the
14760 * console or not.
14761 *
14762 * @param {string} name The name of the instance. NOTE: the provider will be available under `name +
14763                        'Provider'` key.
14764 * @param {(Object|function())} provider If the provider is:
14765 *
14766 *   - `Object`: then it should have a `$get` method. The `$get` method will be invoked using
14767 *     {@link auto.$injector#invoke $injector.invoke()} when an instance needs to be created.
14768 *   - `Constructor`: a new instance of the provider will be created using
14769 *     {@link auto.$injector#instantiate $injector.instantiate()}, then treated as `object`.
14770 *
14771 * @returns {Object} registered provider instance
14772
14773 * @example
14774 *
14775 * The following example shows how to create a simple event tracking service and register it using
14776 * {@link auto.$provide#provider $provide.provider()}.
14777 *
14778 * ```js
14779 *  // Define the eventTracker provider
14780 *  function EventTrackerProvider() {
14781 *    var trackingUrl = '/track';
14782 *
14783 *    // A provider method for configuring where the tracked events should been saved
14784 *    this.setTrackingUrl = function(url) {
14785 *      trackingUrl = url;
14786 *    };
14787 *
14788 *    // The service factory function
14789 *    this.$get = ['$http', function($http) {
14790 *      var trackedEvents = {};
14791 *      return {
14792 *        // Call this to track an event
14793 *        event: function(event) {
14794 *          var count = trackedEvents[event] || 0;
14795 *          count += 1;
14796 *          trackedEvents[event] = count;
14797 *          return count;
14798 *        },
14799 *        // Call this to save the tracked events to the trackingUrl
14800 *        save: function() {
14801 *          $http.post(trackingUrl, trackedEvents);
14802 *        }
14803 *      };
14804 *    }];
14805 *  }
14806 *
14807 *  describe('eventTracker', function() {
14808 *    var postSpy;
14809 *
14810 *    beforeEach(module(function($provide) {
14811 *      // Register the eventTracker provider
14812 *      $provide.provider('eventTracker', EventTrackerProvider);
14813 *    }));
14814 *
14815 *    beforeEach(module(function(eventTrackerProvider) {
14816 *      // Configure eventTracker provider
14817 *      eventTrackerProvider.setTrackingUrl('/custom-track');
14818 *    }));
14819 *
14820 *    it('tracks events', inject(function(eventTracker) {
14821 *      expect(eventTracker.event('login')).toEqual(1);
14822 *      expect(eventTracker.event('login')).toEqual(2);
14823 *    }));
14824 *
14825 *    it('saves to the tracking url', inject(function(eventTracker, $http) {
14826 *      postSpy = spyOn($http, 'post');
14827 *      eventTracker.event('login');
14828 *      eventTracker.save();
14829 *      expect(postSpy).toHaveBeenCalled();
14830 *      expect(postSpy.mostRecentCall.args[0]).not.toEqual('/track');
14831 *      expect(postSpy.mostRecentCall.args[0]).toEqual('/custom-track');
14832 *      expect(postSpy.mostRecentCall.args[1]).toEqual({ 'login': 1 });
14833 *    }));
14834 *  });
14835 * ```
14836 */
14837
14838/**
14839 * @ngdoc method
14840 * @name $provide#factory
14841 * @description
14842 *
14843 * Register a **service factory**, which will be called to return the service instance.
14844 * This is short for registering a service where its provider consists of only a `$get` property,
14845 * which is the given service factory function.
14846 * You should use {@link auto.$provide#factory $provide.factory(getFn)} if you do not need to
14847 * configure your service in a provider.
14848 *
14849 * @param {string} name The name of the instance.
14850 * @param {Function|Array.<string|Function>} $getFn The injectable $getFn for the instance creation.
14851 *                      Internally this is a short hand for `$provide.provider(name, {$get: $getFn})`.
14852 * @returns {Object} registered provider instance
14853 *
14854 * @example
14855 * Here is an example of registering a service
14856 * ```js
14857 *   $provide.factory('ping', ['$http', function($http) {
14858 *     return function ping() {
14859 *       return $http.send('/ping');
14860 *     };
14861 *   }]);
14862 * ```
14863 * You would then inject and use this service like this:
14864 * ```js
14865 *   someModule.controller('Ctrl', ['ping', function(ping) {
14866 *     ping();
14867 *   }]);
14868 * ```
14869 */
14870
14871
14872/**
14873 * @ngdoc method
14874 * @name $provide#service
14875 * @description
14876 *
14877 * Register a **service constructor**, which will be invoked with `new` to create the service
14878 * instance.
14879 * This is short for registering a service where its provider's `$get` property is a factory
14880 * function that returns an instance instantiated by the injector from the service constructor
14881 * function.
14882 *
14883 * Internally it looks a bit like this:
14884 *
14885 * ```
14886 * {
14887 *   $get: function() {
14888 *     return $injector.instantiate(constructor);
14889 *   }
14890 * }
14891 * ```
14892 *
14893 *
14894 * You should use {@link auto.$provide#service $provide.service(class)} if you define your service
14895 * as a type/class.
14896 *
14897 * @param {string} name The name of the instance.
14898 * @param {Function|Array.<string|Function>} constructor An injectable class (constructor function)
14899 *     that will be instantiated.
14900 * @returns {Object} registered provider instance
14901 *
14902 * @example
14903 * Here is an example of registering a service using
14904 * {@link auto.$provide#service $provide.service(class)}.
14905 * ```js
14906 *   var Ping = function($http) {
14907 *     this.$http = $http;
14908 *   };
14909 *
14910 *   Ping.$inject = ['$http'];
14911 *
14912 *   Ping.prototype.send = function() {
14913 *     return this.$http.get('/ping');
14914 *   };
14915 *   $provide.service('ping', Ping);
14916 * ```
14917 * You would then inject and use this service like this:
14918 * ```js
14919 *   someModule.controller('Ctrl', ['ping', function(ping) {
14920 *     ping.send();
14921 *   }]);
14922 * ```
14923 */
14924
14925
14926/**
14927 * @ngdoc method
14928 * @name $provide#value
14929 * @description
14930 *
14931 * Register a **value service** with the {@link auto.$injector $injector}, such as a string, a
14932 * number, an array, an object or a function. This is short for registering a service where its
14933 * provider's `$get` property is a factory function that takes no arguments and returns the **value
14934 * service**. That also means it is not possible to inject other services into a value service.
14935 *
14936 * Value services are similar to constant services, except that they cannot be injected into a
14937 * module configuration function (see {@link angular.Module#config}) but they can be overridden by
14938 * an Angular {@link auto.$provide#decorator decorator}.
14939 *
14940 * @param {string} name The name of the instance.
14941 * @param {*} value The value.
14942 * @returns {Object} registered provider instance
14943 *
14944 * @example
14945 * Here are some examples of creating value services.
14946 * ```js
14947 *   $provide.value('ADMIN_USER', 'admin');
14948 *
14949 *   $provide.value('RoleLookup', { admin: 0, writer: 1, reader: 2 });
14950 *
14951 *   $provide.value('halfOf', function(value) {
14952 *     return value / 2;
14953 *   });
14954 * ```
14955 */
14956
14957
14958/**
14959 * @ngdoc method
14960 * @name $provide#constant
14961 * @description
14962 *
14963 * Register a **constant service** with the {@link auto.$injector $injector}, such as a string,
14964 * a number, an array, an object or a function. Like the {@link auto.$provide#value value}, it is not
14965 * possible to inject other services into a constant.
14966 *
14967 * But unlike {@link auto.$provide#value value}, a constant can be
14968 * injected into a module configuration function (see {@link angular.Module#config}) and it cannot
14969 * be overridden by an Angular {@link auto.$provide#decorator decorator}.
14970 *
14971 * @param {string} name The name of the constant.
14972 * @param {*} value The constant value.
14973 * @returns {Object} registered instance
14974 *
14975 * @example
14976 * Here a some examples of creating constants:
14977 * ```js
14978 *   $provide.constant('SHARD_HEIGHT', 306);
14979 *
14980 *   $provide.constant('MY_COLOURS', ['red', 'blue', 'grey']);
14981 *
14982 *   $provide.constant('double', function(value) {
14983 *     return value * 2;
14984 *   });
14985 * ```
14986 */
14987
14988
14989/**
14990 * @ngdoc method
14991 * @name $provide#decorator
14992 * @description
14993 *
14994 * Register a **decorator function** with the {@link auto.$injector $injector}. A decorator function
14995 * intercepts the creation of a service, allowing it to override or modify the behavior of the
14996 * service. The return value of the decorator function may be the original service, or a new service
14997 * that replaces (or wraps and delegates to) the original service.
14998 *
14999 * You can find out more about using decorators in the {@link guide/decorators} guide.
15000 *
15001 * @param {string} name The name of the service to decorate.
15002 * @param {Function|Array.<string|Function>} decorator This function will be invoked when the service needs to be
15003 *    provided and should return the decorated service instance. The function is called using
15004 *    the {@link auto.$injector#invoke injector.invoke} method and is therefore fully injectable.
15005 *    Local injection arguments:
15006 *
15007 *    * `$delegate` - The original service instance, which can be replaced, monkey patched, configured,
15008 *      decorated or delegated to.
15009 *
15010 * @example
15011 * Here we decorate the {@link ng.$log $log} service to convert warnings to errors by intercepting
15012 * calls to {@link ng.$log#error $log.warn()}.
15013 * ```js
15014 *   $provide.decorator('$log', ['$delegate', function($delegate) {
15015 *     $delegate.warn = $delegate.error;
15016 *     return $delegate;
15017 *   }]);
15018 * ```
15019 */
15020
15021
15022function createInjector(modulesToLoad, strictDi) {
15023  strictDi = (strictDi === true);
15024  var INSTANTIATING = {},
15025      providerSuffix = 'Provider',
15026      path = [],
15027      loadedModules = new NgMap(),
15028      providerCache = {
15029        $provide: {
15030            provider: supportObject(provider),
15031            factory: supportObject(factory),
15032            service: supportObject(service),
15033            value: supportObject(value),
15034            constant: supportObject(constant),
15035            decorator: decorator
15036          }
15037      },
15038      providerInjector = (providerCache.$injector =
15039          createInternalInjector(providerCache, function(serviceName, caller) {
15040            if (angular.isString(caller)) {
15041              path.push(caller);
15042            }
15043            throw $injectorMinErr('unpr', 'Unknown provider: {0}', path.join(' <- '));
15044          })),
15045      instanceCache = {},
15046      protoInstanceInjector =
15047          createInternalInjector(instanceCache, function(serviceName, caller) {
15048            var provider = providerInjector.get(serviceName + providerSuffix, caller);
15049            return instanceInjector.invoke(
15050                provider.$get, provider, undefined, serviceName);
15051          }),
15052      instanceInjector = protoInstanceInjector;
15053
15054  providerCache['$injector' + providerSuffix] = { $get: valueFn(protoInstanceInjector) };
15055  instanceInjector.modules = providerInjector.modules = createMap();
15056  var runBlocks = loadModules(modulesToLoad);
15057  instanceInjector = protoInstanceInjector.get('$injector');
15058  instanceInjector.strictDi = strictDi;
15059  forEach(runBlocks, function(fn) { if (fn) instanceInjector.invoke(fn); });
15060
15061  return instanceInjector;
15062
15063  ////////////////////////////////////
15064  // $provider
15065  ////////////////////////////////////
15066
15067  function supportObject(delegate) {
15068    return function(key, value) {
15069      if (isObject(key)) {
vendor: 5,894 bytes, lines 15070-15238
15070        forEach(key, reverseParams(delegate));
15071      } else {
15072        return delegate(key, value);
15073      }
15074    };
15075  }
15076
15077  function provider(name, provider_) {
15078    assertNotHasOwnProperty(name, 'service');
15079    if (isFunction(provider_) || isArray(provider_)) {
15080      provider_ = providerInjector.instantiate(provider_);
15081    }
15082    if (!provider_.$get) {
15083      throw $injectorMinErr('pget', 'Provider \'{0}\' must define $get factory method.', name);
15084    }
15085    return (providerCache[name + providerSuffix] = provider_);
15086  }
15087
15088  function enforceReturnValue(name, factory) {
15089    return /** @this */ function enforcedReturnValue() {
15090      var result = instanceInjector.invoke(factory, this);
15091      if (isUndefined(result)) {
15092        throw $injectorMinErr('undef', 'Provider \'{0}\' must return a value from $get factory method.', name);
15093      }
15094      return result;
15095    };
15096  }
15097
15098  function factory(name, factoryFn, enforce) {
15099    return provider(name, {
15100      $get: enforce !== false ? enforceReturnValue(name, factoryFn) : factoryFn
15101    });
15102  }
15103
15104  function service(name, constructor) {
15105    return factory(name, ['$injector', function($injector) {
15106      return $injector.instantiate(constructor);
15107    }]);
15108  }
15109
15110  function value(name, val) { return factory(name, valueFn(val), false); }
15111
15112  function constant(name, value) {
15113    assertNotHasOwnProperty(name, 'constant');
15114    providerCache[name] = value;
15115    instanceCache[name] = value;
15116  }
15117
15118  function decorator(serviceName, decorFn) {
15119    var origProvider = providerInjector.get(serviceName + providerSuffix),
15120        orig$get = origProvider.$get;
15121
15122    origProvider.$get = function() {
15123      var origInstance = instanceInjector.invoke(orig$get, origProvider);
15124      return instanceInjector.invoke(decorFn, null, {$delegate: origInstance});
15125    };
15126  }
15127
15128  ////////////////////////////////////
15129  // Module Loading
15130  ////////////////////////////////////
15131  function loadModules(modulesToLoad) {
15132    assertArg(isUndefined(modulesToLoad) || isArray(modulesToLoad), 'modulesToLoad', 'not an array');
15133    var runBlocks = [], moduleFn;
15134    forEach(modulesToLoad, function(module) {
15135      if (loadedModules.get(module)) return;
15136      loadedModules.set(module, true);
15137
15138      function runInvokeQueue(queue) {
15139        var i, ii;
15140        for (i = 0, ii = queue.length; i < ii; i++) {
15141          var invokeArgs = queue[i],
15142              provider = providerInjector.get(invokeArgs[0]);
15143
15144          provider[invokeArgs[1]].apply(provider, invokeArgs[2]);
15145        }
15146      }
15147
15148      try {
15149        if (isString(module)) {
15150          moduleFn = angularModule(module);
15151          instanceInjector.modules[module] = moduleFn;
15152          runBlocks = runBlocks.concat(loadModules(moduleFn.requires)).concat(moduleFn._runBlocks);
15153          runInvokeQueue(moduleFn._invokeQueue);
15154          runInvokeQueue(moduleFn._configBlocks);
15155        } else if (isFunction(module)) {
15156            runBlocks.push(providerInjector.invoke(module));
15157        } else if (isArray(module)) {
15158            runBlocks.push(providerInjector.invoke(module));
15159        } else {
15160          assertArgFn(module, 'module');
15161        }
15162      } catch (e) {
15163        if (isArray(module)) {
15164          module = module[module.length - 1];
15165        }
15166        if (e.message && e.stack && e.stack.indexOf(e.message) === -1) {
15167          // Safari & FF's stack traces don't contain error.message content
15168          // unlike those of Chrome and IE
15169          // So if stack doesn't contain message, we create a new string that contains both.
15170          // Since error.stack is read-only in Safari, I'm overriding e and not e.stack here.
15171          // eslint-disable-next-line no-ex-assign
15172          e = e.message + '\n' + e.stack;
15173        }
15174        throw $injectorMinErr('modulerr', 'Failed to instantiate module {0} due to:\n{1}',
15175                  module, e.stack || e.message || e);
15176      }
15177    });
15178    return runBlocks;
15179  }
15180
15181  ////////////////////////////////////
15182  // internal Injector
15183  ////////////////////////////////////
15184
15185  function createInternalInjector(cache, factory) {
15186
15187    function getService(serviceName, caller) {
15188      if (cache.hasOwnProperty(serviceName)) {
15189        if (cache[serviceName] === INSTANTIATING) {
15190          throw $injectorMinErr('cdep', 'Circular dependency found: {0}',
15191                    serviceName + ' <- ' + path.join(' <- '));
15192        }
15193        return cache[serviceName];
15194      } else {
15195        try {
15196          path.unshift(serviceName);
15197          cache[serviceName] = INSTANTIATING;
15198          cache[serviceName] = factory(serviceName, caller);
15199          return cache[serviceName];
15200        } catch (err) {
15201          if (cache[serviceName] === INSTANTIATING) {
15202            delete cache[serviceName];
15203          }
15204          throw err;
15205        } finally {
15206          path.shift();
15207        }
15208      }
15209    }
15210
15211
15212    function injectionArgs(fn, locals, serviceName) {
15213      var args = [],
15214          $inject = createInjector.$$annotate(fn, strictDi, serviceName);
15215
15216      for (var i = 0, length = $inject.length; i < length; i++) {
15217        var key = $inject[i];
15218        if (typeof key !== 'string') {
15219          throw $injectorMinErr('itkn',
15220                  'Incorrect injection token! Expected service name as string, got {0}', key);
15221        }
15222        args.push(locals && locals.hasOwnProperty(key) ? locals[key] :
15223                                                         getService(key, serviceName));
15224      }
15225      return args;
15226    }
15227
15228    function isClass(func) {
15229      // Support: IE 9-11 only
15230      // IE 9-11 do not support classes and IE9 leaks with the code below.
15231      if (msie || typeof func !== 'function') {
15232        return false;
15233      }
15234      var result = func.$$ngIsClass;
15235      if (!isBoolean(result)) {
15236        // Support: Edge 12-13 only
15237        // See: https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/6156135/
15238        result = func.$$ngIsClass = /^(?:class\b|constructor\()
vendor: 16,448 bytes, lines 15238-15742
15238/.test(stringifyFn(func));
15239      }
15240      return result;
15241    }
15242
15243    function invoke(fn, self, locals, serviceName) {
15244      if (typeof locals === 'string') {
15245        serviceName = locals;
15246        locals = null;
15247      }
15248
15249      var args = injectionArgs(fn, locals, serviceName);
15250      if (isArray(fn)) {
15251        fn = fn[fn.length - 1];
15252      }
15253
15254      if (!isClass(fn)) {
15255        // http://jsperf.com/angularjs-invoke-apply-vs-switch
15256        // #5388
15257        return fn.apply(self, args);
15258      } else {
15259        args.unshift(null);
15260        return new (Function.prototype.bind.apply(fn, args))();
15261      }
15262    }
15263
15264
15265    function instantiate(Type, locals, serviceName) {
15266      // Check if Type is annotated and use just the given function at n-1 as parameter
15267      // e.g. someModule.factory('greeter', ['$window', function(renamed$window) {}]);
15268      var ctor = (isArray(Type) ? Type[Type.length - 1] : Type);
15269      var args = injectionArgs(Type, locals, serviceName);
15270      // Empty object at position 0 is ignored for invocation with `new`, but required.
15271      args.unshift(null);
15272      return new (Function.prototype.bind.apply(ctor, args))();
15273    }
15274
15275
15276    return {
15277      invoke: invoke,
15278      instantiate: instantiate,
15279      get: getService,
15280      annotate: createInjector.$$annotate,
15281      has: function(name) {
15282        return providerCache.hasOwnProperty(name + providerSuffix) || cache.hasOwnProperty(name);
15283      }
15284    };
15285  }
15286}
15287
15288createInjector.$$annotate = annotate;
15289
15290/**
15291 * @ngdoc provider
15292 * @name $anchorScrollProvider
15293 * @this
15294 *
15295 * @description
15296 * Use `$anchorScrollProvider` to disable automatic scrolling whenever
15297 * {@link ng.$location#hash $location.hash()} changes.
15298 */
15299function $AnchorScrollProvider() {
15300
15301  var autoScrollingEnabled = true;
15302
15303  /**
15304   * @ngdoc method
15305   * @name $anchorScrollProvider#disableAutoScrolling
15306   *
15307   * @description
15308   * By default, {@link ng.$anchorScroll $anchorScroll()} will automatically detect changes to
15309   * {@link ng.$location#hash $location.hash()} and scroll to the element matching the new hash.<br />
15310   * Use this method to disable automatic scrolling.
15311   *
15312   * If automatic scrolling is disabled, one must explicitly call
15313   * {@link ng.$anchorScroll $anchorScroll()} in order to scroll to the element related to the
15314   * current hash.
15315   */
15316  this.disableAutoScrolling = function() {
15317    autoScrollingEnabled = false;
15318  };
15319
15320  /**
15321   * @ngdoc service
15322   * @name $anchorScroll
15323   * @kind function
15324   * @requires $window
15325   * @requires $location
15326   * @requires $rootScope
15327   *
15328   * @description
15329   * When called, it scrolls to the element related to the specified `hash` or (if omitted) to the
15330   * current value of {@link ng.$location#hash $location.hash()}, according to the rules specified
15331   * in the
15332   * [HTML5 spec](http://www.w3.org/html/wg/drafts/html/master/browsers.html#an-indicated-part-of-the-document).
15333   *
15334   * It also watches the {@link ng.$location#hash $location.hash()} and automatically scrolls to
15335   * match any anchor whenever it changes. This can be disabled by calling
15336   * {@link ng.$anchorScrollProvider#disableAutoScrolling $anchorScrollProvider.disableAutoScrolling()}.
15337   *
15338   * Additionally, you can use its {@link ng.$anchorScroll#yOffset yOffset} property to specify a
15339   * vertical scroll-offset (either fixed or dynamic).
15340   *
15341   * @param {string=} hash The hash specifying the element to scroll to. If omitted, the value of
15342   *                       {@link ng.$location#hash $location.hash()} will be used.
15343   *
15344   * @property {(number|function|jqLite)} yOffset
15345   * If set, specifies a vertical scroll-offset. This is often useful when there are fixed
15346   * positioned elements at the top of the page, such as navbars, headers etc.
15347   *
15348   * `yOffset` can be specified in various ways:
15349   * - **number**: A fixed number of pixels to be used as offset.<br /><br />
15350   * - **function**: A getter function called everytime `$anchorScroll()` is executed. Must return
15351   *   a number representing the offset (in pixels).<br /><br />
15352   * - **jqLite**: A jqLite/jQuery element to be used for specifying the offset. The distance from
15353   *   the top of the page to the element's bottom will be used as offset.<br />
15354   *   **Note**: The element will be taken into account only as long as its `position` is set to
15355   *   `fixed`. This option is useful, when dealing with responsive navbars/headers that adjust
15356   *   their height and/or positioning according to the viewport's size.
15357   *
15358   * <br />
15359   * <div class="alert alert-warning">
15360   * In order for `yOffset` to work properly, scrolling should take place on the document's root and
15361   * not some child element.
15362   * </div>
15363   *
15364   * @example
15365     <example module="anchorScrollExample" name="anchor-scroll">
15366       <file name="index.html">
15367         <div id="scrollArea" ng-controller="ScrollController">
15368           <a ng-click="gotoBottom()">Go to bottom</a>
15369           <a id="bottom"></a> You're at the bottom!
15370         </div>
15371       </file>
15372       <file name="script.js">
15373         angular.module('anchorScrollExample', [])
15374           .controller('ScrollController', ['$scope', '$location', '$anchorScroll',
15375             function($scope, $location, $anchorScroll) {
15376               $scope.gotoBottom = function() {
15377                 // set the location.hash to the id of
15378                 // the element you wish to scroll to.
15379                 $location.hash('bottom');
15380
15381                 // call $anchorScroll()
15382                 $anchorScroll();
15383               };
15384             }]);
15385       </file>
15386       <file name="style.css">
15387         #scrollArea {
15388           height: 280px;
15389           overflow: auto;
15390         }
15391
15392         #bottom {
15393           display: block;
15394           margin-top: 2000px;
15395         }
15396       </file>
15397     </example>
15398   *
15399   * <hr />
15400   * The example below illustrates the use of a vertical scroll-offset (specified as a fixed value).
15401   * See {@link ng.$anchorScroll#yOffset $anchorScroll.yOffset} for more details.
15402   *
15403   * @example
15404     <example module="anchorScrollOffsetExample" name="anchor-scroll-offset">
15405       <file name="index.html">
15406         <div class="fixed-header" ng-controller="headerCtrl">
15407           <a href="" ng-click="gotoAnchor(x)" ng-repeat="x in [1,2,3,4,5]">
15408             Go to anchor {{x}}
15409           </a>
15410         </div>
15411         <div id="anchor{{x}}" class="anchor" ng-repeat="x in [1,2,3,4,5]">
15412           Anchor {{x}} of 5
15413         </div>
15414       </file>
15415       <file name="script.js">
15416         angular.module('anchorScrollOffsetExample', [])
15417           .run(['$anchorScroll', function($anchorScroll) {
15418             $anchorScroll.yOffset = 50;   // always scroll by 50 extra pixels
15419           }])
15420           .controller('headerCtrl', ['$anchorScroll', '$location', '$scope',
15421             function($anchorScroll, $location, $scope) {
15422               $scope.gotoAnchor = function(x) {
15423                 var newHash = 'anchor' + x;
15424                 if ($location.hash() !== newHash) {
15425                   // set the $location.hash to `newHash` and
15426                   // $anchorScroll will automatically scroll to it
15427                   $location.hash('anchor' + x);
15428                 } else {
15429                   // call $anchorScroll() explicitly,
15430                   // since $location.hash hasn't changed
15431                   $anchorScroll();
15432                 }
15433               };
15434             }
15435           ]);
15436       </file>
15437       <file name="style.css">
15438         body {
15439           padding-top: 50px;
15440         }
15441
15442         .anchor {
15443           border: 2px dashed DarkOrchid;
15444           padding: 10px 10px 200px 10px;
15445         }
15446
15447         .fixed-header {
15448           background-color: rgba(0, 0, 0, 0.2);
15449           height: 50px;
15450           position: fixed;
15451           top: 0; left: 0; right: 0;
15452         }
15453
15454         .fixed-header > a {
15455           display: inline-block;
15456           margin: 5px 15px;
15457         }
15458       </file>
15459     </example>
15460   */
15461  this.$get = ['$window', '$location', '$rootScope', function($window, $location, $rootScope) {
15462    var document = $window.document;
15463
15464    // Helper function to get first anchor from a NodeList
15465    // (using `Array#some()` instead of `angular#forEach()` since it's more performant
15466    //  and working in all supported browsers.)
15467    function getFirstAnchor(list) {
15468      var result = null;
15469      Array.prototype.some.call(list, function(element) {
15470        if (nodeName_(element) === 'a') {
15471          result = element;
15472          return true;
15473        }
15474      });
15475      return result;
15476    }
15477
15478    function getYOffset() {
15479
15480      var offset = scroll.yOffset;
15481
15482      if (isFunction(offset)) {
15483        offset = offset();
15484      } else if (isElement(offset)) {
15485        var elem = offset[0];
15486        var style = $window.getComputedStyle(elem);
15487        if (style.position !== 'fixed') {
15488          offset = 0;
15489        } else {
15490          offset = elem.getBoundingClientRect().bottom;
15491        }
15492      } else if (!isNumber(offset)) {
15493        offset = 0;
15494      }
15495
15496      return offset;
15497    }
15498
15499    function scrollTo(elem) {
15500      if (elem) {
15501        elem.scrollIntoView();
15502
15503        var offset = getYOffset();
15504
15505        if (offset) {
15506          // `offset` is the number of pixels we should scroll UP in order to align `elem` properly.
15507          // This is true ONLY if the call to `elem.scrollIntoView()` initially aligns `elem` at the
15508          // top of the viewport.
15509          //
15510          // IF the number of pixels from the top of `elem` to the end of the page's content is less
15511          // than the height of the viewport, then `elem.scrollIntoView()` will align the `elem` some
15512          // way down the page.
15513          //
15514          // This is often the case for elements near the bottom of the page.
15515          //
15516          // In such cases we do not need to scroll the whole `offset` up, just the difference between
15517          // the top of the element and the offset, which is enough to align the top of `elem` at the
15518          // desired position.
15519          var elemTop = elem.getBoundingClientRect().top;
15520          $window.scrollBy(0, elemTop - offset);
15521        }
15522      } else {
15523        $window.scrollTo(0, 0);
15524      }
15525    }
15526
15527    function scroll(hash) {
15528      // Allow numeric hashes
15529      hash = isString(hash) ? hash : isNumber(hash) ? hash.toString() : $location.hash();
15530      var elm;
15531
15532      // empty hash, scroll to the top of the page
15533      if (!hash) scrollTo(null);
15534
15535      // element with given id
15536      else if ((elm = document.getElementById(hash))) scrollTo(elm);
15537
15538      // first anchor with given name :-D
15539      else if ((elm = getFirstAnchor(document.getElementsByName(hash)))) scrollTo(elm);
15540
15541      // no element and hash === 'top', scroll to the top of the page
15542      else if (hash === 'top') scrollTo(null);
15543    }
15544
15545    // does not scroll when user clicks on anchor link that is currently on
15546    // (no url change, no $location.hash() change), browser native does scroll
15547    if (autoScrollingEnabled) {
15548      $rootScope.$watch(function autoScrollWatch() {return $location.hash();},
15549        function autoScrollWatchAction(newVal, oldVal) {
15550          // skip the initial scroll if $location.hash is empty
15551          if (newVal === oldVal && newVal === '') return;
15552
15553          jqLiteDocumentLoaded(function() {
15554            $rootScope.$evalAsync(scroll);
15555          });
15556        });
15557    }
15558
15559    return scroll;
15560  }];
15561}
15562
15563var $animateMinErr = minErr('$animate');
15564var ELEMENT_NODE = 1;
15565var NG_ANIMATE_CLASSNAME = 'ng-animate';
15566
15567function mergeClasses(a,b) {
15568  if (!a && !b) return '';
15569  if (!a) return b;
15570  if (!b) return a;
15571  if (isArray(a)) a = a.join(' ');
15572  if (isArray(b)) b = b.join(' ');
15573  return a + ' ' + b;
15574}
15575
15576function extractElementNode(element) {
15577  for (var i = 0; i < element.length; i++) {
15578    var elm = element[i];
15579    if (elm.nodeType === ELEMENT_NODE) {
15580      return elm;
15581    }
15582  }
15583}
15584
15585function splitClasses(classes) {
15586  if (isString(classes)) {
15587    classes = classes.split(' ');
15588  }
15589
15590  // Use createMap() to prevent class assumptions involving property names in
15591  // Object.prototype
15592  var obj = createMap();
15593  forEach(classes, function(klass) {
15594    // sometimes the split leaves empty string values
15595    // incase extra spaces were applied to the options
15596    if (klass.length) {
15597      obj[klass] = true;
15598    }
15599  });
15600  return obj;
15601}
15602
15603// if any other type of options value besides an Object value is
15604// passed into the $animate.method() animation then this helper code
15605// will be run which will ignore it. While this patch is not the
15606// greatest solution to this, a lot of existing plugins depend on
15607// $animate to either call the callback (< 1.2) or return a promise
15608// that can be changed. This helper function ensures that the options
15609// are wiped clean incase a callback function is provided.
15610function prepareAnimateOptions(options) {
15611  return isObject(options)
15612      ? options
15613      : {};
15614}
15615
15616var $$CoreAnimateJsProvider = /** @this */ function() {
15617  this.$get = noop;
15618};
15619
15620// this is prefixed with Core since it conflicts with
15621// the animateQueueProvider defined in ngAnimate/animateQueue.js
15622var $$CoreAnimateQueueProvider = /** @this */ function() {
15623  var postDigestQueue = new NgMap();
15624  var postDigestElements = [];
15625
15626  this.$get = ['$$AnimateRunner', '$rootScope',
15627       function($$AnimateRunner,   $rootScope) {
15628    return {
15629      enabled: noop,
15630      on: noop,
15631      off: noop,
15632      pin: noop,
15633
15634      push: function(element, event, options, domOperation) {
15635        if (domOperation) {
15636          domOperation();
15637        }
15638
15639        options = options || {};
15640        if (options.from) {
15641          element.css(options.from);
15642        }
15643        if (options.to) {
15644          element.css(options.to);
15645        }
15646
15647        if (options.addClass || options.removeClass) {
15648          addRemoveClassesPostDigest(element, options.addClass, options.removeClass);
15649        }
15650
15651        var runner = new $$AnimateRunner();
15652
15653        // since there are no animations to run the runner needs to be
15654        // notified that the animation call is complete.
15655        runner.complete();
15656        return runner;
15657      }
15658    };
15659
15660
15661    function updateData(data, classes, value) {
15662      var changed = false;
15663      if (classes) {
15664        classes = isString(classes) ? classes.split(' ') :
15665                  isArray(classes) ? classes : [];
15666        forEach(classes, function(className) {
15667          if (className) {
15668            changed = true;
15669            data[className] = value;
15670          }
15671        });
15672      }
15673      return changed;
15674    }
15675
15676    function handleCSSClassChanges() {
15677      forEach(postDigestElements, function(element) {
15678        var data = postDigestQueue.get(element);
15679        if (data) {
15680          var existing = splitClasses(element.attr('class'));
15681          var toAdd = '';
15682          var toRemove = '';
15683          forEach(data, function(status, className) {
15684            var hasClass = !!existing[className];
15685            if (status !== hasClass) {
15686              if (status) {
15687                toAdd += (toAdd.length ? ' ' : '') + className;
15688              } else {
15689                toRemove += (toRemove.length ? ' ' : '') + className;
15690              }
15691            }
15692          });
15693
15694          forEach(element, function(elm) {
15695            if (toAdd) {
15696              jqLiteAddClass(elm, toAdd);
15697            }
15698            if (toRemove) {
15699              jqLiteRemoveClass(elm, toRemove);
15700            }
15701          });
15702          postDigestQueue.delete(element);
15703        }
15704      });
15705      postDigestElements.length = 0;
15706    }
15707
15708
15709    function addRemoveClassesPostDigest(element, add, remove) {
15710      var data = postDigestQueue.get(element) || {};
15711
15712      var classesAdded = updateData(data, add, true);
15713      var classesRemoved = updateData(data, remove, false);
15714
15715      if (classesAdded || classesRemoved) {
15716
15717        postDigestQueue.set(element, data);
15718        postDigestElements.push(element);
15719
15720        if (postDigestElements.length === 1) {
15721          $rootScope.$$postDigest(handleCSSClassChanges);
15722        }
15723      }
15724    }
15725  }];
15726};
15727
15728/**
15729 * @ngdoc provider
15730 * @name $animateProvider
15731 *
15732 * @description
15733 * Default implementation of $animate that doesn't perform any animations, instead just
15734 * synchronously performs DOM updates and resolves the returned runner promise.
15735 *
15736 * In order to enable animations the `ngAnimate` module has to be loaded.
15737 *
15738 * To see the functional implementation check out `src/ngAnimate/animate.js`.
15739 */
15740var $AnimateProvider = ['$provide', /** @this */ function($provide) {
15741  var provider = this;
15742  var classNameFilter = null;
15743
15744  this.$$registeredAnimations = Object.create(null);
15745
15746   /**
15747   * @ngdoc method
15748   * @name $animateProvider#register
15749   *
15750   * @description
15751   * Registers a new injectable animation factory function. The factory function produces the
15752   * animation object which contains callback functions for each event that is expected to be
15753   * animated.
15754   *
15755   *   * `eventFn`: `function(element, ... , doneFunction, options)`
15756   *   The element to animate, the `doneFunction` and the options fed into the animation. Depending
15757   *   on the type of animation additional arguments will be injected into the animation function. The
15758   *   list below explains the function signatures for the different animation methods:
15759   *
15760   *   - setClass: function(element, addedClasses, removedClasses, doneFunction, options)
15761   *   - addClass: function(element, addedClasses, doneFunction, options)
15762   *   - removeClass: function(element, removedClasses, doneFunction, options)
15763   *   - enter, leave, move: function(element, doneFunction, options)
15764   *   - animate: function(element, fromStyles, toStyles, doneFunction, options)
15765   *
15766   *   Make sure to trigger the `doneFunction` once the animation is fully complete.
15767   *
15768   * ```js
15769   *   return {
15770   *     //enter, leave, move signature
15771   *     eventFn : function(element, done, options) {
15772   *       //code to run the animation
15773   *       //once complete, then run done()
15774   *       return function endFunction(wasCancelled) {
15775   *         //code to cancel the animation
15776   *       }
15777   *     }
15778   *   }
15779   * ```
15780   *
15781   * @param {string} name The name of the animation (this is what the class-based CSS value will be compared to).
15782   * @param {Function} factory The factory function that will be executed to return the animation
15783   *                           object.
15784   */
15785  this.register = function(name, factory) {
15786    if (name && name.charAt(0) !== '.') {
15787      throw $animateMinErr('notcsel', 'Expecting class selector starting with \'.\' got \'{0}\'.', name);
15788    }
15789
15790    var key = name + '-animation';
15791    provider.$$registeredAnimations[name.substr(1)] = key;
15792    $provide.factory(key, factory);
15793  };
15794
15795  /**
15796   * @ngdoc method
15797   * @name $animateProvider#classNameFilter
15798   *
15799   * @description
15800   * Sets and/or returns the CSS class regular expression that is checked when performing
15801   * an animation. Upon bootstrap the classNameFilter value is not set at all and will
15802   * therefore enable $animate to attempt to perform an animation on any element that is triggered.
15803   * When setting the `classNameFilter` value, animations will only be performed on elements
15804   * that successfully match the filter expression. This in turn can boost performance
15805   * for low-powered devices as well as applications containing a lot of structural operations.
15806   * @param {RegExp=} expression The className expression which will be checked against all animations
15807   * @return {RegExp} The current CSS className expression value. If null then there is no expression value
15808   */
15809  this.classNameFilter = function(expression) {
15810    if (arguments.length === 1) {
15811      classNameFilter = (expression instanceof RegExp) ? expression : null;
15812      if (classNameFilter) {
15813        var reservedRegex = new RegExp('[(\\s|\\/)]' + NG_ANIMATE_CLASSNAME + '[(\\s|\\/)]');
15814        if (reservedRegex.test(classNameFilter.toString())) {
15815          classNameFilter = null;
15816          throw $animateMinErr('nongcls', '$animateProvider.classNameFilter(regex) prohibits accepting a regex value which matches/contains the "{0}" CSS class.', NG_ANIMATE_CLASSNAME);
15817        }
15818      }
15819    }
15820    return classNameFilter;
15821  };
15822
15823  this.$get = ['$$animateQueue', function($$animateQueue) {
15824    function domInsert(element, parentElement, afterElement) {
15825      // if for some reason the previous element was removed
15826      // from the dom sometime before this code runs then let's
15827      // just stick to using the parent element as the anchor
15828      if (afterElement) {
15829        var afterNode = extractElementNode(afterElement);
15830        if (afterNode && !afterNode.parentNode && !afterNode.previousElementSibling) {
15831          afterElement = null;
15832        }
15833      }
15834      if (afterElement) {
15835        afterElement.after(element);
15836      } else {
15837        parentElement.prepend(element);
15838      }
15839    }
15840
15841    /**
15842     * @ngdoc service
15843     * @name $animate
15844     * @description The $animate service exposes a series of DOM utility methods that provide support
15845     * for animation hooks. The default behavior is the application of DOM operations, however,
15846     * when an animation is detected (and animations are enabled), $animate will do the heavy lifting
15847     * to ensure that animation runs with the triggered DOM operation.
15848     *
15849     * By default $animate doesn't trigger any animations. This is because the `ngAnimate` module isn't
15850     * included and only when it is active then the animation hooks that `$animate` triggers will be
15851     * functional. Once active then all structural `ng-` directives will trigger animations as they perform
15852     * their DOM-related operations (enter, leave and move). Other directives such as `ngClass`,
15853     * `ngShow`, `ngHide` and `ngMessages` also provide support for animations.
15854     *
15855     * It is recommended that the`$animate` service is always used when executing DOM-related procedures within directives.
15856     *
15857     * To learn more about enabling animation support, click here to visit the
15858     * {@link ngAnimate ngAnimate module page}.
15859     */
15860    return {
15861      // we don't call it directly since non-existant arguments may
15862      // be interpreted as null within the sub enabled function
15863
15864      /**
15865       *
15866       * @ngdoc method
15867       * @name $animate#on
15868       * @kind function
15869       * @description Sets up an event listener to fire whenever the animation event (enter, leave, move, etc...)
15870       *    has fired on the given element or among any of its children. Once the listener is fired, the provided callback
15871       *    is fired with the following params:
15872       *
15873       * ```js
15874       * $animate.on('enter', container,
15875       *    function callback(element, phase) {
15876       *      // cool we detected an enter animation within the container
15877       *    }
15878       * );
15879       * ```
15880       *
15881       * @param {string} event the animation event that will be captured (e.g. enter, leave, move, addClass, removeClass, etc...)
15882       * @param {DOMElement} container the container element that will capture each of the animation events that are fired on itself
15883       *     as well as among its children
15884       * @param {Function} callback the callback function that will be fired when the listener is triggered
15885       *
15886       * The arguments present in the callback function are:
15887       * * `element` - The captured DOM element that the animation was fired on.
15888       * * `phase` - The phase of the animation. The two possible phases are **start** (when the animation starts) and **close** (when it ends).
15889       */
15890      on: $$animateQueue.on,
15891
15892      /**
15893       *
15894       * @ngdoc method
15895       * @name $animate#off
15896       * @kind function
15897       * @description Deregisters an event listener based on the event which has been associated with the provided element. This method
15898       * can be used in three different ways depending on the arguments:
15899       *
15900       * ```js
15901       * // remove all the animation event listeners listening for `enter`
15902       * $animate.off('enter');
15903       *
15904       * // remove listeners for all animation events from the container element
15905       * $animate.off(container);
15906       *
15907       * // remove all the animation event listeners listening for `enter` on the given element and its children
15908       * $animate.off('enter', container);
15909       *
15910       * // remove the event listener function provided by `callback` that is set
15911       * // to listen for `enter` on the given `container` as well as its children
15912       * $animate.off('enter', container, callback);
15913       * ```
15914       *
15915       * @param {string|DOMElement} event|container the animation event (e.g. enter, leave, move,
15916       * addClass, removeClass, etc...), or the container element. If it is the element, all other
15917       * arguments are ignored.
15918       * @param {DOMElement=} container the container element the event listener was placed on
15919       * @param {Function=} callback the callback function that was registered as the listener
15920       */
15921      off: $$animateQueue.off,
15922
15923      /**
15924       * @ngdoc method
15925       * @name $animate#pin
15926       * @kind function
15927       * @description Associates the provided element with a host parent element to allow the element to be animated even if it exists
15928       *    outside of the DOM structure of the Angular application. By doing so, any animation triggered via `$animate` can be issued on the
15929       *    element despite being outside the realm of the application or within another application. Say for example if the application
15930       *    was bootstrapped on an element that is somewhere inside of the `<body>` tag, but we wanted to allow for an element to be situated
15931       *    as a direct child of `document.body`, then this can be achieved by pinning the element via `$animate.pin(element)`. Keep in mind
15932       *    that calling `$animate.pin(element, parentElement)` will not actually insert into the DOM anywhere; it will just create the association.
15933       *
15934       *    Note that this feature is only active when the `ngAnimate` module is used.
15935       *
15936       * @param {DOMElement} element the external element that will be pinned
15937       * @param {DOMElement} parentElement the host parent element that will be associated with the external element
15938       */
15939      pin: $$animateQueue.pin,
15940
15941      /**
15942       *
15943       * @ngdoc method
15944       * @name $animate#enabled
15945       * @kind function
15946       * @description Used to get and set whether animations are enabled or not on the entire application or on an element and its children. This
15947       * function can be called in four ways:
15948       *
15949       * ```js
15950       * // returns true or false
15951       * $animate.enabled();
15952       *
15953       * // changes the enabled state for all animations
15954       * $animate.enabled(false);
15955       * $animate.enabled(true);
15956       *
15957       * // returns true or false if animations are enabled for an element
15958       * $animate.enabled(element);
15959       *
15960       * // changes the enabled state for an element and its children
15961       * $animate.enabled(element, true);
15962       * $animate.enabled(element, false);
15963       * ```
15964       *
15965       * @param {DOMElement=} element the element that will be considered for checking/setting the enabled state
15966       * @param {boolean=} enabled whether or not the animations will be enabled for the element
15967       *
15968       * @return {boolean} whether or not animations are enabled
15969       */
15970      enabled: $$animateQueue.enabled,
15971
15972      /**
15973       * @ngdoc method
15974       * @name $animate#cancel
15975       * @kind function
15976       * @description Cancels the provided animation.
15977       *
15978       * @param {Promise} animationPromise The animation promise that is returned when an animation is started.
15979       */
15980      cancel: function(runner) {
15981        if (runner.end) {
15982          runner.end();
15983        }
15984      },
15985
15986      /**
15987       *
15988       * @ngdoc method
15989       * @name $animate#enter
15990       * @kind function
15991       * @description Inserts the element into the DOM either after the `after` element (if provided) or
15992       *   as the first child within the `parent` element and then triggers an animation.
15993       *   A promise is returned that will be resolved during the next digest once the animation
15994       *   has completed.
15995       *
15996       * @param {DOMElement} element the element which will be inserted into the DOM
15997       * @param {DOMElement} parent the parent element which will append the element as
15998       *   a child (so long as the after element is not present)
15999       * @param {DOMElement=} after the sibling element after which the element will be appended
16000       * @param {object=} options an optional collection of options/styles that will be applied to the element.
16001       *   The object can have the following properties:
16002       *
16003       *   - **addClass** - `{string}` - space-separated CSS classes to add to element
16004       *   - **from** - `{Object}` - CSS properties & values at the beginning of animation. Must have matching `to`
16005       *   - **removeClass** - `{string}` - space-separated CSS classes to remove from element
16006       *   - **to** - `{Object}` - CSS properties & values at end of animation. Must have matching `from`
16007       *
16008       * @return {Promise} the animation callback promise
16009       */
16010      enter: function(element, parent, after, options) {
16011        parent = parent && jqLite(parent);
16012        after = after && jqLite(after);
16013        parent = parent || after.parent();
16014        domInsert(element, parent, after);
16015        return $$animateQueue.push(element, 'enter', prepareAnimateOptions(options));
16016      },
16017
16018      /**
16019       *
16020       * @ngdoc method
16021       * @name $animate#move
16022       * @kind function
16023       * @description Inserts (moves) the element into its new position in the DOM either after
16024       *   the `after` element (if provided) or as the first child within the `parent` element
16025       *   and then triggers an animation. A promise is returned that will be resolved
16026       *   during the next digest once the animation has completed.
16027       *
16028       * @param {DOMElement} element the element which will be moved into the new DOM position
16029       * @param {DOMElement} parent the parent element which will append the element as
16030       *   a child (so long as the after element is not present)
16031       * @param {DOMElement=} after the sibling element after which the element will be appended
16032       * @param {object=} options an optional collection of options/styles that will be applied to the element.
16033       *   The object can have the following properties:
16034       *
16035       *   - **addClass** - `{string}` - space-separated CSS classes to add to element
16036       *   - **from** - `{Object}` - CSS properties & values at the beginning of animation. Must have matching `to`
16037       *   - **removeClass** - `{string}` - space-separated CSS classes to remove from element
16038       *   - **to** - `{Object}` - CSS properties & values at end of animation. Must have matching `from`
16039       *
16040       * @return {Promise} the animation callback promise
16041       */
16042      move: function(element, parent, after, options) {
16043        parent = parent && jqLite(parent);
16044        after = after && jqLite(after);
16045        parent = parent || after.parent();
16046        domInsert(element, parent, after);
16047        return $$animateQueue.push(element, 'move', prepareAnimateOptions(options));
16048      },
16049
16050      /**
16051       * @ngdoc method
16052       * @name $animate#leave
16053       * @kind function
16054       * @description Triggers an animation and then removes the element from the DOM.
16055       * When the function is called a promise is returned that will be resolved during the next
16056       * digest once the animation has completed.
16057       *
16058       * @param {DOMElement} element the element which will be removed from the DOM
16059       * @param {object=} options an optional collection of options/styles that will be applied to the element.
16060       *   The object can have the following properties:
16061       *
16062       *   - **addClass** - `{string}` - space-separated CSS classes to add to element
16063       *   - **from** - `{Object}` - CSS properties & values at the beginning of animation. Must have matching `to`
16064       *   - **removeClass** - `{string}` - space-separated CSS classes to remove from element
16065       *   - **to** - `{Object}` - CSS properties & values at end of animation. Must have matching `from`
16066       *
16067       * @return {Promise} the animation callback promise
16068       */
16069      leave: function(element, options) {
16070        return $$animateQueue.push(element, 'leave', prepareAnimateOptions(options), function() {
16071          element.remove();
16072        });
16073      },
16074
16075      /**
16076       * @ngdoc method
16077       * @name $animate#addClass
16078       * @kind function
16079       *
16080       * @description Triggers an addClass animation surrounding the addition of the provided CSS class(es). Upon
16081       *   execution, the addClass operation will only be handled after the next digest and it will not trigger an
16082       *   animation if element already contains the CSS class or if the class is removed at a later step.
16083       *   Note that class-based animations are treated differently compared to structural animations
16084       *   (like enter, move and leave) since the CSS classes may be added/removed at different points
16085       *   depending if CSS or JavaScript animations are used.
16086       *
16087       * @param {DOMElement} element the element which the CSS classes will be applied to
16088       * @param {string} className the CSS class(es) that will be added (multiple classes are separated via spaces)
16089       * @param {object=} options an optional collection of options/styles that will be applied to the element.
16090       *   The object can have the following properties:
16091       *
16092       *   - **addClass** - `{string}` - space-separated CSS classes to add to element
16093       *   - **from** - `{Object}` - CSS properties & values at the beginning of animation. Must have matching `to`
16094       *   - **removeClass** - `{string}` - space-separated CSS classes to remove from element
16095       *   - **to** - `{Object}` - CSS properties & values at end of animation. Must have matching `from`
16096       *
16097       * @return {Promise} the animation callback promise
16098       */
16099      addClass: function(element, className, options) {
16100        options = prepareAnimateOptions(options);
16101        options.addClass = mergeClasses(options.addclass, className);
16102        return $$animateQueue.push(element, 'addClass', options);
16103      },
16104
16105      /**
16106       * @ngdoc method
16107       * @name $animate#removeClass
16108       * @kind function
16109       *
16110       * @description Triggers a removeClass animation surrounding the removal of the provided CSS class(es). Upon
16111       *   execution, the removeClass operation will only be handled after the next digest and it will not trigger an
16112       *   animation if element does not contain the CSS class or if the class is added at a later step.
16113       *   Note that class-based animations are treated differently compared to structural animations
16114       *   (like enter, move and leave) since the CSS classes may be added/removed at different points
16115       *   depending if CSS or JavaScript animations are used.
16116       *
16117       * @param {DOMElement} element the element which the CSS classes will be applied to
16118       * @param {string} className the CSS class(es) that will be removed (multiple classes are separated via spaces)
16119       * @param {object=} options an optional collection of options/styles that will be applied to the element.
16120       *   The object can have the following properties:
16121       *
16122       *   - **addClass** - `{string}` - space-separated CSS classes to add to element
16123       *   - **from** - `{Object}` - CSS properties & values at the beginning of animation. Must have matching `to`
16124       *   - **removeClass** - `{string}` - space-separated CSS classes to remove from element
16125       *   - **to** - `{Object}` - CSS properties & values at end of animation. Must have matching `from`
16126       *
16127       * @return {Promise} the animation callback promise
16128       */
16129      removeClass: function(element, className, options) {
16130        options = prepareAnimateOptions(options);
16131        options.removeClass = mergeClasses(options.removeClass, className);
16132        return $$animateQueue.push(element, 'removeClass', options);
16133      },
16134
16135      /**
16136       * @ngdoc method
16137       * @name $animate#setClass
16138       * @kind function
16139       *
16140       * @description Performs both the addition and removal of a CSS classes on an element and (during the process)
16141       *    triggers an animation surrounding the class addition/removal. Much like `$animate.addClass` and
16142       *    `$animate.removeClass`, `setClass` will only evaluate the classes being added/removed once a digest has
16143       *    passed. Note that class-based animations are treated differently compared to structural animations
16144       *    (like enter, move and leave) since the CSS classes may be added/removed at different points
16145       *    depending if CSS or JavaScript animations are used.
16146       *
16147       * @param {DOMElement} element the element which the CSS classes will be applied to
16148       * @param {string} add the CSS class(es) that will be added (multiple classes are separated via spaces)
16149       * @param {string} remove the CSS class(es) that will be removed (multiple classes are separated via spaces)
16150       * @param {object=} options an optional collection of options/styles that will be applied to the element.
16151       *   The object can have the following properties:
16152       *
16153       *   - **addClass** - `{string}` - space-separated CSS classes to add to element
16154       *   - **from** - `{Object}` - CSS properties & values at the beginning of animation. Must have matching `to`
16155       *   - **removeClass** - `{string}` - space-separated CSS classes to remove from element
16156       *   - **to** - `{Object}` - CSS properties & values at end of animation. Must have matching `from`
16157       *
16158       * @return {Promise} the animation callback promise
16159       */
16160      setClass: function(element, add, remove, options) {
16161        options = prepareAnimateOptions(options);
16162        options.addClass = mergeClasses(options.addClass, add);
16163        options.removeClass = mergeClasses(options.removeClass, remove);
16164        return $$animateQueue.push(element, 'setClass', options);
16165      },
16166
16167      /**
16168       * @ngdoc method
16169       * @name $animate#animate
16170       * @kind function
16171       *
16172       * @description Performs an inline animation on the element which applies the provided to and from CSS styles to the element.
16173       * If any detected CSS transition, keyframe or JavaScript matches the provided className value, then the animation will take
16174       * on the provided styles. For example, if a transition animation is set for the given className, then the provided `from` and
16175       * `to` styles will be applied alongside the given transition. If the CSS style provided in `from` does not have a corresponding
16176       * style in `to`, the style in `from` is applied immediately, and no animation is run.
16177       * If a JavaScript animation is detected then the provided styles will be given in as function parameters into the `animate`
16178       * method (or as part of the `options` parameter):
16179       *
16180       * ```js
16181       * ngModule.animation('.my-inline-animation', function() {
16182       *   return {
16183       *     animate : function(element, from, to, done, options) {
16184       *       //animation
16185       *       done();
16186       *     }
16187       *   }
16188       * });
16189       * ```
16190       *
16191       * @param {DOMElement} element the element which the CSS styles will be applied to
16192       * @param {object} from the from (starting) CSS styles that will be applied to the element and across the animation.
16193       * @param {object} to the to (destination) CSS styles that will be applied to the element and across the animation.
16194       * @param {string=} className an optional CSS class that will be applied to the element for the duration of the animation. If
16195       *    this value is left as empty then a CSS class of `ng-inline-animate` will be applied to the element.
16196       *    (Note that if no animation is detected then this value will not be applied to the element.)
16197       * @param {object=} options an optional collection of options/styles that will be applied to the element.
16198       *   The object can have the following properties:
16199       *
16200       *   - **addClass** - `{string}` - space-separated CSS classes to add to element
16201       *   - **from** - `{Object}` - CSS properties & values at the beginning of animation. Must have matching `to`
16202       *   - **removeClass** - `{string}` - space-separated CSS classes to remove from element
16203       *   - **to** - `{Object}` - CSS properties & values at end of animation. Must have matching `from`
16204       *
16205       * @return {Promise} the animation callback promise
16206       */
16207      animate: function(element, from, to, className, options) {
16208        options = prepareAnimateOptions(options);
16209        options.from = options.from ? extend(options.from, from) : from;
16210        options.to   = options.to   ? extend(options.to, to)     : to;
16211
16212        className = className || 'ng-inline-animate';
16213        options.tempClasses = mergeClasses(options.tempClasses, className);
16214        return $$animateQueue.push(element, 'animate', options);
16215      }
16216    };
16217  }];
16218}];
16219
16220var $$AnimateAsyncRunFactoryProvider = /** @this */ function() {
16221  this.$get = ['$$rAF', function($$rAF) {
16222    var waitQueue = [];
16223
16224    function waitForTick(fn) {
16225      waitQueue.push(fn);
16226      if (waitQueue.length > 1) return;
16227      $$rAF(function() {
16228        for (var i = 0; i < waitQueue.length; i++) {
16229          waitQueue[i]();
16230        }
16231        waitQueue = [];
16232      });
16233    }
16234
16235    return function() {
16236      var passed = false;
16237      waitForTick(function() {
16238        passed = true;
16239      });
16240      return function(callback) {
16241        if (passed) {
16242          callback();
16243        } else {
16244          waitForTick(callback);
16245        }
16246      };
16247    };
16248  }];
16249};
16250
16251var $$AnimateRunnerFactoryProvider = /** @this */ function() {
16252  this.$get = ['$q', '$sniffer', '$$animateAsyncRun', '$$isDocumentHidden', '$timeout',
16253       function($q,   $sniffer,   $$animateAsyncRun,   $$isDocumentHidden,   $timeout) {
16254
16255    var INITIAL_STATE = 0;
16256    var DONE_PENDING_STATE = 1;
16257    var DONE_COMPLETE_STATE = 2;
16258
16259    AnimateRunner.chain = function(chain, callback) {
16260      var index = 0;
16261
16262      next();
16263      function next() {
16264        if (index === chain.length) {
16265          callback(true);
16266          return;
16267        }
16268
16269        chain[index](function(response) {
16270          if (response === false) {
16271            callback(false);
16272            return;
16273          }
16274          index++;
16275          next();
16276        });
16277      }
16278    };
16279
16280    AnimateRunner.all = function(runners, callback) {
16281      var count = 0;
16282      var status = true;
vendor: 5,133 bytes, lines 16283-16495
16283      forEach(runners, function(runner) {
16284        runner.done(onProgress);
16285      });
16286
16287      function onProgress(response) {
16288        status = status && response;
16289        if (++count === runners.length) {
16290          callback(status);
16291        }
16292      }
16293    };
16294
16295    function AnimateRunner(host) {
16296      this.setHost(host);
16297
16298      var rafTick = $$animateAsyncRun();
16299      var timeoutTick = function(fn) {
16300        $timeout(fn, 0, false);
16301      };
16302
16303      this._doneCallbacks = [];
16304      this._tick = function(fn) {
16305        if ($$isDocumentHidden()) {
16306          timeoutTick(fn);
16307        } else {
16308          rafTick(fn);
16309        }
16310      };
16311      this._state = 0;
16312    }
16313
16314    AnimateRunner.prototype = {
16315      setHost: function(host) {
16316        this.host = host || {};
16317      },
16318
16319      done: function(fn) {
16320        if (this._state === DONE_COMPLETE_STATE) {
16321          fn();
16322        } else {
16323          this._doneCallbacks.push(fn);
16324        }
16325      },
16326
16327      progress: noop,
16328
16329      getPromise: function() {
16330        if (!this.promise) {
16331          var self = this;
16332          this.promise = $q(function(resolve, reject) {
16333            self.done(function(status) {
16334              if (status === false) {
16335                reject();
16336              } else {
16337                resolve();
16338              }
16339            });
16340          });
16341        }
16342        return this.promise;
16343      },
16344
16345      then: function(resolveHandler, rejectHandler) {
16346        return this.getPromise().then(resolveHandler, rejectHandler);
16347      },
16348
16349      'catch': function(handler) {
16350        return this.getPromise()['catch'](handler);
16351      },
16352
16353      'finally': function(handler) {
16354        return this.getPromise()['finally'](handler);
16355      },
16356
16357      pause: function() {
16358        if (this.host.pause) {
16359          this.host.pause();
16360        }
16361      },
16362
16363      resume: function() {
16364        if (this.host.resume) {
16365          this.host.resume();
16366        }
16367      },
16368
16369      end: function() {
16370        if (this.host.end) {
16371          this.host.end();
16372        }
16373        this._resolve(true);
16374      },
16375
16376      cancel: function() {
16377        if (this.host.cancel) {
16378          this.host.cancel();
16379        }
16380        this._resolve(false);
16381      },
16382
16383      complete: function(response) {
16384        var self = this;
16385        if (self._state === INITIAL_STATE) {
16386          self._state = DONE_PENDING_STATE;
16387          self._tick(function() {
16388            self._resolve(response);
16389          });
16390        }
16391      },
16392
16393      _resolve: function(response) {
16394        if (this._state !== DONE_COMPLETE_STATE) {
16395          forEach(this._doneCallbacks, function(fn) {
16396            fn(response);
16397          });
16398          this._doneCallbacks.length = 0;
16399          this._state = DONE_COMPLETE_STATE;
16400        }
16401      }
16402    };
16403
16404    return AnimateRunner;
16405  }];
16406};
16407
16408/* exported $CoreAnimateCssProvider */
16409
16410/**
16411 * @ngdoc service
16412 * @name $animateCss
16413 * @kind object
16414 * @this
16415 *
16416 * @description
16417 * This is the core version of `$animateCss`. By default, only when the `ngAnimate` is included,
16418 * then the `$animateCss` service will actually perform animations.
16419 *
16420 * Click here {@link ngAnimate.$animateCss to read the documentation for $animateCss}.
16421 */
16422var $CoreAnimateCssProvider = function() {
16423  this.$get = ['$$rAF', '$q', '$$AnimateRunner', function($$rAF, $q, $$AnimateRunner) {
16424
16425    return function(element, initialOptions) {
16426      // all of the animation functions should create
16427      // a copy of the options data, however, if a
16428      // parent service has already created a copy then
16429      // we should stick to using that
16430      var options = initialOptions || {};
16431      if (!options.$$prepared) {
16432        options = copy(options);
16433      }
16434
16435      // there is no point in applying the styles since
16436      // there is no animation that goes on at all in
16437      // this version of $animateCss.
16438      if (options.cleanupStyles) {
16439        options.from = options.to = null;
16440      }
16441
16442      if (options.from) {
16443        element.css(options.from);
16444        options.from = null;
16445      }
16446
16447      var closed, runner = new $$AnimateRunner();
16448      return {
16449        start: run,
16450        end: run
16451      };
16452
16453      function run() {
16454        $$rAF(function() {
16455          applyAnimationContents();
16456          if (!closed) {
16457            runner.complete();
16458          }
16459          closed = true;
16460        });
16461        return runner;
16462      }
16463
16464      function applyAnimationContents() {
16465        if (options.addClass) {
16466          element.addClass(options.addClass);
16467          options.addClass = null;
16468        }
16469        if (options.removeClass) {
16470          element.removeClass(options.removeClass);
16471          options.removeClass = null;
16472        }
16473        if (options.to) {
16474          element.css(options.to);
16475          options.to = null;
16476        }
16477      }
16478    };
16479  }];
16480};
16481
16482/* global stripHash: true */
16483
16484/**
16485 * ! This is a private undocumented service !
16486 *
16487 * @name $browser
16488 * @requires $log
16489 * @description
16490 * This object has two goals:
16491 *
16492 * - hide all the global state in the browser caused by the window object
16493 * - abstract away all the browser specific features and inconsistencies
16494 *
16495 * For tests we provide {@link ngMock.$browser mock implementation} of the `$browser`
16496 * service, which can be used for convenient testing of the application without the interaction with
16497 * the real browser apis.
16498 */
16499/**
16500 * @param {object} window The global window object.
16501 * @param {object} document jQuery wrapped document.
16502 * @param {object} $log window.console or an object with the same interface.
16503 * @param {object} $sniffer $sniffer service
16504 */
16505function Browser(window, document, $log, $sniffer) {
16506  var self = this,
16507      location = window.location,
16508      history = window.history,
16509      setTimeout = window.setTimeout,
16510      clearTimeout = window.clearTimeout,
16511      pendingDeferIds = {};
16512
16513  self.isMock = false;
16514
16515  var outstandingRequestCount = 0;
16516  var outstandingRequestCallbacks = [];
16517
16518  // TODO(vojta): remove this temporary api
16519  self.$$completeOutstandingRequest = completeOutstandingRequest;
16520  self.$$incOutstandingRequestCount = function() { outstandingRequestCount++; };
16521
16522  /**
16523   * Executes the `fn` function(supports currying) and decrements the `outstandingRequestCallbacks`
16524   * counter. If the counter reaches 0, all the `outstandingRequestCallbacks` are executed.
16525   */
16526  function completeOutstandingRequest(fn) {
16527    try {
16528      fn.apply(null, sliceArgs(arguments, 1));
16529    } finally {
16530      outstandingRequestCount--;
16531      if (outstandingRequestCount === 0) {
16532        while (outstandingRequestCallbacks.length) {
16533          try {
16534            outstandingRequestCallbacks.pop()();
16535          } catch (e) {
16536            $log.error(e);
16537          }
16538        }
16539      }
16540    }
16541  }
16542
16543  function getHash(url) {
16544    var index = url.indexOf('#');
16545    return index === -1 ? '' : url.substr(index);
16546  }
16547
16548  /**
16549   * @private
16550   * Note: this method is used only by scenario runner
16551   * TODO(vojta): prefix this method with $$ ?
16552   * @param {function()} callback Function that will be called when no outstanding request
16553   */
16554  self.notifyWhenNoOutstandingRequests = function(callback) {
16555    if (outstandingRequestCount === 0) {
16556      callback();
16557    } else {
16558      outstandingRequestCallbacks.push(callback);
16559    }
16560  };
16561
16562  //////////////////////////////////////////////////////////////
16563  // URL API
16564  //////////////////////////////////////////////////////////////
16565
16566  var cachedState, lastHistoryState,
16567      lastBrowserUrl = location.href,
16568      baseElement = document.find('base'),
16569      pendingLocation = null,
16570      getCurrentState = !$sniffer.history ? noop : function getCurrentState() {
16571        try {
16572          return history.state;
16573        } catch (e) {
16574          // MSIE can reportedly throw when there is no state (UNCONFIRMED).
16575        }
16576      };
16577
16578  cacheState();
16579
16580  /**
16581   * @name $browser#url
16582   *
16583   * @description
16584   * GETTER:
16585   * Without any argument, this method just returns current value of location.href.
16586   *
16587   * SETTER:
16588   * With at least one argument, this method sets url to new value.
16589   * If html5 history api supported, pushState/replaceState is used, otherwise
16590   * location.href/location.replace is used.
16591   * Returns its own instance to allow chaining
16592   *
16593   * NOTE: this api is intended for use only by the $location service. Please use the
16594   * {@link ng.$location $location service} to change url.
16595   *
16596   * @param {string} url New url (when used as setter)
16597   * @param {boolean=} replace Should new url replace current history record?
16598   * @param {object=} state object to use with pushState/replaceState
16599   */
16600  self.url = function(url, replace, state) {
16601    // In modern browsers `history.state` is `null` by default; treating it separately
16602    // from `undefined` would cause `$browser.url('/foo')` to change `history.state`
16603    // to undefined via `pushState`. Instead, let's change `undefined` to `null` here.
16604    if (isUndefined(state)) {
16605      state = null;
16606    }
16607
16608    // Android Browser BFCache causes location, history reference to become stale.
16609    if (location !== window.location) location = window.location;
16610    if (history !== window.history) history = window.history;
16611
16612    // setter
16613    if (url) {
16614      var sameState = lastHistoryState === state;
16615
16616      // Don't change anything if previous and current URLs and states match. This also prevents
16617      // IE<10 from getting into redirect loop when in LocationHashbangInHtml5Url mode.
16618      // See https://github.com/angular/angular.js/commit/ffb2701
16619      if (lastBrowserUrl === url && (!$sniffer.history || sameState)) {
16620        return self;
16621      }
16622      var sameBase = lastBrowserUrl && stripHash(lastBrowserUrl) === stripHash(url);
16623      lastBrowserUrl = url;
16624      lastHistoryState = state;
16625      // Don't use history API if only the hash changed
16626      // due to a bug in IE10/IE11 which leads
16627      // to not firing a `hashchange` nor `popstate` event
16628      // in some cases (see #9143).
16629      if ($sniffer.history && (!sameBase || !sameState)) {
16630        history[replace ? 'replaceState' : 'pushState'](state, '', url);
16631        cacheState();
16632      } else {
16633        if (!sameBase) {
16634          pendingLocation = url;
16635        }
16636        if (replace) {
16637          location.replace(url);
16638        } else if (!sameBase) {
16639          location.href = url;
16640        } else {
16641          location.hash = getHash(url);
16642        }
16643        if (location.href !== url) {
16644          pendingLocation = url;
16645        }
16646      }
16647      if (pendingLocation) {
16648        pendingLocation = url;
16649      }
16650      return self;
16651    // getter
16652    } else {
16653      // - pendingLocation is needed as browsers don't allow to read out
16654      //   the new location.href if a reload happened or if there is a bug like in iOS 9 (see
16655      //   https://openradar.appspot.com/22186109).
16656      // - the replacement is a workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=407172
16657      return pendingLocation || location.href.replace(/%27/g,'\'');
16658    }
16659  };
16660
16661  /**
16662   * @name $browser#state
16663   *
16664   * @description
16665   * This method is a getter.
16666   *
16667   * Return history.state or null if history.state is undefined.
16668   *
16669   * @returns {object} state
16670   */
16671  self.state = function() {
16672    return cachedState;
16673  };
16674
16675  var urlChangeListeners = [],
16676      urlChangeInit = false;
vendor: 16,994 bytes, lines 16677-17242
16677
16678  function cacheStateAndFireUrlChange() {
16679    pendingLocation = null;
16680    fireStateOrUrlChange();
16681  }
16682
16683  // This variable should be used *only* inside the cacheState function.
16684  var lastCachedState = null;
16685  function cacheState() {
16686    // This should be the only place in $browser where `history.state` is read.
16687    cachedState = getCurrentState();
16688    cachedState = isUndefined(cachedState) ? null : cachedState;
16689
16690    // Prevent callbacks fo fire twice if both hashchange & popstate were fired.
16691    if (equals(cachedState, lastCachedState)) {
16692      cachedState = lastCachedState;
16693    }
16694
16695    lastCachedState = cachedState;
16696    lastHistoryState = cachedState;
16697  }
16698
16699  function fireStateOrUrlChange() {
16700    var prevLastHistoryState = lastHistoryState;
16701    cacheState();
16702
16703    if (lastBrowserUrl === self.url() && prevLastHistoryState === cachedState) {
16704      return;
16705    }
16706
16707    lastBrowserUrl = self.url();
16708    lastHistoryState = cachedState;
16709    forEach(urlChangeListeners, function(listener) {
16710      listener(self.url(), cachedState);
16711    });
16712  }
16713
16714  /**
16715   * @name $browser#onUrlChange
16716   *
16717   * @description
16718   * Register callback function that will be called, when url changes.
16719   *
16720   * It's only called when the url is changed from outside of angular:
16721   * - user types different url into address bar
16722   * - user clicks on history (forward/back) button
16723   * - user clicks on a link
16724   *
16725   * It's not called when url is changed by $browser.url() method
16726   *
16727   * The listener gets called with new url as parameter.
16728   *
16729   * NOTE: this api is intended for use only by the $location service. Please use the
16730   * {@link ng.$location $location service} to monitor url changes in angular apps.
16731   *
16732   * @param {function(string)} listener Listener function to be called when url changes.
16733   * @return {function(string)} Returns the registered listener fn - handy if the fn is anonymous.
16734   */
16735  self.onUrlChange = function(callback) {
16736    // TODO(vojta): refactor to use node's syntax for events
16737    if (!urlChangeInit) {
16738      // We listen on both (hashchange/popstate) when available, as some browsers don't
16739      // fire popstate when user changes the address bar and don't fire hashchange when url
16740      // changed by push/replaceState
16741
16742      // html5 history api - popstate event
16743      if ($sniffer.history) jqLite(window).on('popstate', cacheStateAndFireUrlChange);
16744      // hashchange event
16745      jqLite(window).on('hashchange', cacheStateAndFireUrlChange);
16746
16747      urlChangeInit = true;
16748    }
16749
16750    urlChangeListeners.push(callback);
16751    return callback;
16752  };
16753
16754  /**
16755   * @private
16756   * Remove popstate and hashchange handler from window.
16757   *
16758   * NOTE: this api is intended for use only by $rootScope.
16759   */
16760  self.$$applicationDestroyed = function() {
16761    jqLite(window).off('hashchange popstate', cacheStateAndFireUrlChange);
16762  };
16763
16764  /**
16765   * Checks whether the url has changed outside of Angular.
16766   * Needs to be exported to be able to check for changes that have been done in sync,
16767   * as hashchange/popstate events fire in async.
16768   */
16769  self.$$checkUrlChange = fireStateOrUrlChange;
16770
16771  //////////////////////////////////////////////////////////////
16772  // Misc API
16773  //////////////////////////////////////////////////////////////
16774
16775  /**
16776   * @name $browser#baseHref
16777   *
16778   * @description
16779   * Returns current <base href>
16780   * (always relative - without domain)
16781   *
16782   * @returns {string} The current base href
16783   */
16784  self.baseHref = function() {
16785    var href = baseElement.attr('href');
16786    return href ? href.replace(/^(https?:)?\/\/[^/]*/, '') : '';
16787  };
16788
16789  /**
16790   * @name $browser#defer
16791   * @param {function()} fn A function, who's execution should be deferred.
16792   * @param {number=} [delay=0] of milliseconds to defer the function execution.
16793   * @returns {*} DeferId that can be used to cancel the task via `$browser.defer.cancel()`.
16794   *
16795   * @description
16796   * Executes a fn asynchronously via `setTimeout(fn, delay)`.
16797   *
16798   * Unlike when calling `setTimeout` directly, in test this function is mocked and instead of using
16799   * `setTimeout` in tests, the fns are queued in an array, which can be programmatically flushed
16800   * via `$browser.defer.flush()`.
16801   *
16802   */
16803  self.defer = function(fn, delay) {
16804    var timeoutId;
16805    outstandingRequestCount++;
16806    timeoutId = setTimeout(function() {
16807      delete pendingDeferIds[timeoutId];
16808      completeOutstandingRequest(fn);
16809    }, delay || 0);
16810    pendingDeferIds[timeoutId] = true;
16811    return timeoutId;
16812  };
16813
16814
16815  /**
16816   * @name $browser#defer.cancel
16817   *
16818   * @description
16819   * Cancels a deferred task identified with `deferId`.
16820   *
16821   * @param {*} deferId Token returned by the `$browser.defer` function.
16822   * @returns {boolean} Returns `true` if the task hasn't executed yet and was successfully
16823   *                    canceled.
16824   */
16825  self.defer.cancel = function(deferId) {
16826    if (pendingDeferIds[deferId]) {
16827      delete pendingDeferIds[deferId];
16828      clearTimeout(deferId);
16829      completeOutstandingRequest(noop);
16830      return true;
16831    }
16832    return false;
16833  };
16834
16835}
16836
16837/** @this */
16838function $BrowserProvider() {
16839  this.$get = ['$window', '$log', '$sniffer', '$document',
16840      function($window, $log, $sniffer, $document) {
16841        return new Browser($window, $document, $log, $sniffer);
16842      }];
16843}
16844
16845/**
16846 * @ngdoc service
16847 * @name $cacheFactory
16848 * @this
16849 *
16850 * @description
16851 * Factory that constructs {@link $cacheFactory.Cache Cache} objects and gives access to
16852 * them.
16853 *
16854 * ```js
16855 *
16856 *  var cache = $cacheFactory('cacheId');
16857 *  expect($cacheFactory.get('cacheId')).toBe(cache);
16858 *  expect($cacheFactory.get('noSuchCacheId')).not.toBeDefined();
16859 *
16860 *  cache.put("key", "value");
16861 *  cache.put("another key", "another value");
16862 *
16863 *  // We've specified no options on creation
16864 *  expect(cache.info()).toEqual({id: 'cacheId', size: 2});
16865 *
16866 * ```
16867 *
16868 *
16869 * @param {string} cacheId Name or id of the newly created cache.
16870 * @param {object=} options Options object that specifies the cache behavior. Properties:
16871 *
16872 *   - `{number=}` `capacity` — turns the cache into LRU cache.
16873 *
16874 * @returns {object} Newly created cache object with the following set of methods:
16875 *
16876 * - `{object}` `info()` — Returns id, size, and options of cache.
16877 * - `{{*}}` `put({string} key, {*} value)` — Puts a new key-value pair into the cache and returns
16878 *   it.
16879 * - `{{*}}` `get({string} key)` — Returns cached value for `key` or undefined for cache miss.
16880 * - `{void}` `remove({string} key)` — Removes a key-value pair from the cache.
16881 * - `{void}` `removeAll()` — Removes all cached values.
16882 * - `{void}` `destroy()` — Removes references to this cache from $cacheFactory.
16883 *
16884 * @example
16885   <example module="cacheExampleApp" name="cache-factory">
16886     <file name="index.html">
16887       <div ng-controller="CacheController">
16888         <input ng-model="newCacheKey" placeholder="Key">
16889         <input ng-model="newCacheValue" placeholder="Value">
16890         <button ng-click="put(newCacheKey, newCacheValue)">Cache</button>
16891
16892         <p ng-if="keys.length">Cached Values</p>
16893         <div ng-repeat="key in keys">
16894           <span ng-bind="key"></span>
16895           <span>: </span>
16896           <b ng-bind="cache.get(key)"></b>
16897         </div>
16898
16899         <p>Cache Info</p>
16900         <div ng-repeat="(key, value) in cache.info()">
16901           <span ng-bind="key"></span>
16902           <span>: </span>
16903           <b ng-bind="value"></b>
16904         </div>
16905       </div>
16906     </file>
16907     <file name="script.js">
16908       angular.module('cacheExampleApp', []).
16909         controller('CacheController', ['$scope', '$cacheFactory', function($scope, $cacheFactory) {
16910           $scope.keys = [];
16911           $scope.cache = $cacheFactory('cacheId');
16912           $scope.put = function(key, value) {
16913             if (angular.isUndefined($scope.cache.get(key))) {
16914               $scope.keys.push(key);
16915             }
16916             $scope.cache.put(key, angular.isUndefined(value) ? null : value);
16917           };
16918         }]);
16919     </file>
16920     <file name="style.css">
16921       p {
16922         margin: 10px 0 3px;
16923       }
16924     </file>
16925   </example>
16926 */
16927function $CacheFactoryProvider() {
16928
16929  this.$get = function() {
16930    var caches = {};
16931
16932    function cacheFactory(cacheId, options) {
16933      if (cacheId in caches) {
16934        throw minErr('$cacheFactory')('iid', 'CacheId \'{0}\' is already taken!', cacheId);
16935      }
16936
16937      var size = 0,
16938          stats = extend({}, options, {id: cacheId}),
16939          data = createMap(),
16940          capacity = (options && options.capacity) || Number.MAX_VALUE,
16941          lruHash = createMap(),
16942          freshEnd = null,
16943          staleEnd = null;
16944
16945      /**
16946       * @ngdoc type
16947       * @name $cacheFactory.Cache
16948       *
16949       * @description
16950       * A cache object used to store and retrieve data, primarily used by
16951       * {@link $http $http} and the {@link ng.directive:script script} directive to cache
16952       * templates and other data.
16953       *
16954       * ```js
16955       *  angular.module('superCache')
16956       *    .factory('superCache', ['$cacheFactory', function($cacheFactory) {
16957       *      return $cacheFactory('super-cache');
16958       *    }]);
16959       * ```
16960       *
16961       * Example test:
16962       *
16963       * ```js
16964       *  it('should behave like a cache', inject(function(superCache) {
16965       *    superCache.put('key', 'value');
16966       *    superCache.put('another key', 'another value');
16967       *
16968       *    expect(superCache.info()).toEqual({
16969       *      id: 'super-cache',
16970       *      size: 2
16971       *    });
16972       *
16973       *    superCache.remove('another key');
16974       *    expect(superCache.get('another key')).toBeUndefined();
16975       *
16976       *    superCache.removeAll();
16977       *    expect(superCache.info()).toEqual({
16978       *      id: 'super-cache',
16979       *      size: 0
16980       *    });
16981       *  }));
16982       * ```
16983       */
16984      return (caches[cacheId] = {
16985
16986        /**
16987         * @ngdoc method
16988         * @name $cacheFactory.Cache#put
16989         * @kind function
16990         *
16991         * @description
16992         * Inserts a named entry into the {@link $cacheFactory.Cache Cache} object to be
16993         * retrieved later, and incrementing the size of the cache if the key was not already
16994         * present in the cache. If behaving like an LRU cache, it will also remove stale
16995         * entries from the set.
16996         *
16997         * It will not insert undefined values into the cache.
16998         *
16999         * @param {string} key the key under which the cached data is stored.
17000         * @param {*} value the value to store alongside the key. If it is undefined, the key
17001         *    will not be stored.
17002         * @returns {*} the value stored.
17003         */
17004        put: function(key, value) {
17005          if (isUndefined(value)) return;
17006          if (capacity < Number.MAX_VALUE) {
17007            var lruEntry = lruHash[key] || (lruHash[key] = {key: key});
17008
17009            refresh(lruEntry);
17010          }
17011
17012          if (!(key in data)) size++;
17013          data[key] = value;
17014
17015          if (size > capacity) {
17016            this.remove(staleEnd.key);
17017          }
17018
17019          return value;
17020        },
17021
17022        /**
17023         * @ngdoc method
17024         * @name $cacheFactory.Cache#get
17025         * @kind function
17026         *
17027         * @description
17028         * Retrieves named data stored in the {@link $cacheFactory.Cache Cache} object.
17029         *
17030         * @param {string} key the key of the data to be retrieved
17031         * @returns {*} the value stored.
17032         */
17033        get: function(key) {
17034          if (capacity < Number.MAX_VALUE) {
17035            var lruEntry = lruHash[key];
17036
17037            if (!lruEntry) return;
17038
17039            refresh(lruEntry);
17040          }
17041
17042          return data[key];
17043        },
17044
17045
17046        /**
17047         * @ngdoc method
17048         * @name $cacheFactory.Cache#remove
17049         * @kind function
17050         *
17051         * @description
17052         * Removes an entry from the {@link $cacheFactory.Cache Cache} object.
17053         *
17054         * @param {string} key the key of the entry to be removed
17055         */
17056        remove: function(key) {
17057          if (capacity < Number.MAX_VALUE) {
17058            var lruEntry = lruHash[key];
17059
17060            if (!lruEntry) return;
17061
17062            if (lruEntry === freshEnd) freshEnd = lruEntry.p;
17063            if (lruEntry === staleEnd) staleEnd = lruEntry.n;
17064            link(lruEntry.n,lruEntry.p);
17065
17066            delete lruHash[key];
17067          }
17068
17069          if (!(key in data)) return;
17070
17071          delete data[key];
17072          size--;
17073        },
17074
17075
17076        /**
17077         * @ngdoc method
17078         * @name $cacheFactory.Cache#removeAll
17079         * @kind function
17080         *
17081         * @description
17082         * Clears the cache object of any entries.
17083         */
17084        removeAll: function() {
17085          data = createMap();
17086          size = 0;
17087          lruHash = createMap();
17088          freshEnd = staleEnd = null;
17089        },
17090
17091
17092        /**
17093         * @ngdoc method
17094         * @name $cacheFactory.Cache#destroy
17095         * @kind function
17096         *
17097         * @description
17098         * Destroys the {@link $cacheFactory.Cache Cache} object entirely,
17099         * removing it from the {@link $cacheFactory $cacheFactory} set.
17100         */
17101        destroy: function() {
17102          data = null;
17103          stats = null;
17104          lruHash = null;
17105          delete caches[cacheId];
17106        },
17107
17108
17109        /**
17110         * @ngdoc method
17111         * @name $cacheFactory.Cache#info
17112         * @kind function
17113         *
17114         * @description
17115         * Retrieve information regarding a particular {@link $cacheFactory.Cache Cache}.
17116         *
17117         * @returns {object} an object with the following properties:
17118         *   <ul>
17119         *     <li>**id**: the id of the cache instance</li>
17120         *     <li>**size**: the number of entries kept in the cache instance</li>
17121         *     <li>**...**: any additional properties from the options object when creating the
17122         *       cache.</li>
17123         *   </ul>
17124         */
17125        info: function() {
17126          return extend({}, stats, {size: size});
17127        }
17128      });
17129
17130
17131      /**
17132       * makes the `entry` the freshEnd of the LRU linked list
17133       */
17134      function refresh(entry) {
17135        if (entry !== freshEnd) {
17136          if (!staleEnd) {
17137            staleEnd = entry;
17138          } else if (staleEnd === entry) {
17139            staleEnd = entry.n;
17140          }
17141
17142          link(entry.n, entry.p);
17143          link(entry, freshEnd);
17144          freshEnd = entry;
17145          freshEnd.n = null;
17146        }
17147      }
17148
17149
17150      /**
17151       * bidirectionally links two entries of the LRU linked list
17152       */
17153      function link(nextEntry, prevEntry) {
17154        if (nextEntry !== prevEntry) {
17155          if (nextEntry) nextEntry.p = prevEntry; //p stands for previous, 'prev' didn't minify
17156          if (prevEntry) prevEntry.n = nextEntry; //n stands for next, 'next' didn't minify
17157        }
17158      }
17159    }
17160
17161
17162  /**
17163   * @ngdoc method
17164   * @name $cacheFactory#info
17165   *
17166   * @description
17167   * Get information about all the caches that have been created
17168   *
17169   * @returns {Object} - key-value map of `cacheId` to the result of calling `cache#info`
17170   */
17171    cacheFactory.info = function() {
17172      var info = {};
17173      forEach(caches, function(cache, cacheId) {
17174        info[cacheId] = cache.info();
17175      });
17176      return info;
17177    };
17178
17179
17180  /**
17181   * @ngdoc method
17182   * @name $cacheFactory#get
17183   *
17184   * @description
17185   * Get access to a cache object by the `cacheId` used when it was created.
17186   *
17187   * @param {string} cacheId Name or id of a cache to access.
17188   * @returns {object} Cache object identified by the cacheId or undefined if no such cache.
17189   */
17190    cacheFactory.get = function(cacheId) {
17191      return caches[cacheId];
17192    };
17193
17194
17195    return cacheFactory;
17196  };
17197}
17198
17199/**
17200 * @ngdoc service
17201 * @name $templateCache
17202 * @this
17203 *
17204 * @description
17205 * The first time a template is used, it is loaded in the template cache for quick retrieval. You
17206 * can load templates directly into the cache in a `script` tag, or by consuming the
17207 * `$templateCache` service directly.
17208 *
17209 * Adding via the `script` tag:
17210 *
17211 * ```html
17212 *   <script type="text/ng-template" id="templateId.html">
17213 *     <p>This is the content of the template</p>
17214 *   </script>
17215 * ```
17216 *
17217 * **Note:** the `script` tag containing the template does not need to be included in the `head` of
17218 * the document, but it must be a descendent of the {@link ng.$rootElement $rootElement} (IE,
17219 * element with ng-app attribute), otherwise the template will be ignored.
17220 *
17221 * Adding via the `$templateCache` service:
17222 *
17223 * ```js
17224 * var myApp = angular.module('myApp', []);
17225 * myApp.run(function($templateCache) {
17226 *   $templateCache.put('templateId.html', 'This is the content of the template');
17227 * });
17228 * ```
17229 *
17230 * To retrieve the template later, simply use it in your component:
17231 * ```js
17232 * myApp.component('myComponent', {
17233 *    templateUrl: 'templateId.html'
17234 * });
17235 * ```
17236 *
17237 * or get it via the `$templateCache` service:
17238 * ```js
17239 * $templateCache.get('templateId.html')
17240 * ```
17241 *
17242 * See {@link ng.$cacheFactory $cacheFactory}.
vendor: 5,589 bytes, lines 17242-17371
17242
17243 *
17244 */
17245function $TemplateCacheProvider() {
17246  this.$get = ['$cacheFactory', function($cacheFactory) {
17247    return $cacheFactory('templates');
17248  }];
17249}
17250
17251/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
17252 *     Any commits to this file should be reviewed with security in mind.  *
17253 *   Changes to this file can potentially create security vulnerabilities. *
17254 *          An approval from 2 Core members with history of modifying      *
17255 *                         this file is required.                          *
17256 *                                                                         *
17257 *  Does the change somehow allow for arbitrary javascript to be executed? *
17258 *    Or allows for someone to change the prototype of built-in objects?   *
17259 *     Or gives undesired access to variables like document or window?    *
17260 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
17261
17262/* ! VARIABLE/FUNCTION NAMING CONVENTIONS THAT APPLY TO THIS FILE!
17263 *
17264 * DOM-related variables:
17265 *
17266 * - "node" - DOM Node
17267 * - "element" - DOM Element or Node
17268 * - "$node" or "$element" - jqLite-wrapped node or element
17269 *
17270 *
17271 * Compiler related stuff:
17272 *
17273 * - "linkFn" - linking fn of a single directive
17274 * - "nodeLinkFn" - function that aggregates all linking fns for a particular node
17275 * - "childLinkFn" -  function that aggregates all linking fns for child nodes of a particular node
17276 * - "compositeLinkFn" - function that aggregates all linking fns for a compilation root (nodeList)
17277 */
17278
17279
17280/**
17281 * @ngdoc service
17282 * @name $compile
17283 * @kind function
17284 *
17285 * @description
17286 * Compiles an HTML string or DOM into a template and produces a template function, which
17287 * can then be used to link {@link ng.$rootScope.Scope `scope`} and the template together.
17288 *
17289 * The compilation is a process of walking the DOM tree and matching DOM elements to
17290 * {@link ng.$compileProvider#directive directives}.
17291 *
17292 * <div class="alert alert-warning">
17293 * **Note:** This document is an in-depth reference of all directive options.
17294 * For a gentle introduction to directives with examples of common use cases,
17295 * see the {@link guide/directive directive guide}.
17296 * </div>
17297 *
17298 * ## Comprehensive Directive API
17299 *
17300 * There are many different options for a directive.
17301 *
17302 * The difference resides in the return value of the factory function.
17303 * You can either return a {@link $compile#directive-definition-object Directive Definition Object (see below)}
17304 * that defines the directive properties, or just the `postLink` function (all other properties will have
17305 * the default values).
17306 *
17307 * <div class="alert alert-success">
17308 * **Best Practice:** It's recommended to use the "directive definition object" form.
17309 * </div>
17310 *
17311 * Here's an example directive declared with a Directive Definition Object:
17312 *
17313 * ```js
17314 *   var myModule = angular.module(...);
17315 *
17316 *   myModule.directive('directiveName', function factory(injectables) {
17317 *     var directiveDefinitionObject = {
17318 *       {@link $compile#-priority- priority}: 0,
17319 *       {@link $compile#-template- template}: '<div></div>', // or // function(tElement, tAttrs) { ... },
17320 *       // or
17321 *       // {@link $compile#-templateurl- templateUrl}: 'directive.html', // or // function(tElement, tAttrs) { ... },
17322 *       {@link $compile#-transclude- transclude}: false,
17323 *       {@link $compile#-restrict- restrict}: 'A',
17324 *       {@link $compile#-templatenamespace- templateNamespace}: 'html',
17325 *       {@link $compile#-scope- scope}: false,
17326 *       {@link $compile#-controller- controller}: function($scope, $element, $attrs, $transclude, otherInjectables) { ... },
17327 *       {@link $compile#-controlleras- controllerAs}: 'stringIdentifier',
17328 *       {@link $compile#-bindtocontroller- bindToController}: false,
17329 *       {@link $compile#-require- require}: 'siblingDirectiveName', // or // ['^parentDirectiveName', '?optionalDirectiveName', '?^optionalParent'],
17330 *       {@link $compile#-multielement- multiElement}: false,
17331 *       {@link $compile#-compile- compile}: function compile(tElement, tAttrs, transclude) {
17332 *         return {
17333 *            {@link $compile#pre-linking-function pre}: function preLink(scope, iElement, iAttrs, controller) { ... },
17334 *            {@link $compile#post-linking-function post}: function postLink(scope, iElement, iAttrs, controller) { ... }
17335 *         }
17336 *         // or
17337 *         // return function postLink( ... ) { ... }
17338 *       },
17339 *       // or
17340 *       // {@link $compile#-link- link}: {
17341 *       //  {@link $compile#pre-linking-function pre}: function preLink(scope, iElement, iAttrs, controller) { ... },
17342 *       //  {@link $compile#post-linking-function post}: function postLink(scope, iElement, iAttrs, controller) { ... }
17343 *       // }
17344 *       // or
17345 *       // {@link $compile#-link- link}: function postLink( ... ) { ... }
17346 *     };
17347 *     return directiveDefinitionObject;
17348 *   });
17349 * ```
17350 *
17351 * <div class="alert alert-warning">
17352 * **Note:** Any unspecified options will use the default value. You can see the default values below.
17353 * </div>
17354 *
17355 * Therefore the above can be simplified as:
17356 *
17357 * ```js
17358 *   var myModule = angular.module(...);
17359 *
17360 *   myModule.directive('directiveName', function factory(injectables) {
17361 *     var directiveDefinitionObject = {
17362 *       link: function postLink(scope, iElement, iAttrs) { ... }
17363 *     };
17364 *     return directiveDefinitionObject;
17365 *     // or
17366 *     // return function postLink(scope, iElement, iAttrs) { ... }
17367 *   });
17368 * ```
17369 *
17370 * ### Life-cycle hooks
17371 * Directive controllers can provide the following methods that are called by Angular
17371 at points in the life-cycle of the
17372 * directive:
17373 * * `$onInit()` - Called on each controller after all the controllers on an element have been constructed and
17374 *   had their bindings initialized (and before the pre &amp; post linking functions for the directives on
17375 *   this element). This is a good place to put initialization code for your controller.
17376 * * `$onChanges(changesObj)` - Called whenever one-way (`<`) or interpolation (`@`) bindings are updated. The
17377 *   `changesObj` is a hash whose keys are the names of the bound properties that have changed, and the values are an
17378 *   object of the form `{ currentValue, previousValue, isFirstChange() }`. Use this hook to trigger updates within a
17379 *   component such as cloning the bound value to prevent accidental mutation of the outer value. Note that this will
17380 *   also be called when your bindings are initialized.
17381 * * `$doCheck()` - Called on each turn of the digest cycle. Provides an opportunity to detect and act on
17382 *   changes. Any actions that you wish to take in response to the changes that you detect must be
17383 *   invoked from this hook; implementing this has no effect on when `$onChanges` is called. For example, this hook
17384 *   could be useful if you wish to perform a deep equality check, or to check a Date object, changes to which w
17384ould not
17385 *   be detected by Angular's change detector and thus not trigger `$onChanges`. This hook is invoked with no arguments;
17386 *   if detecting changes, you must store the previous value(s) for comparison to the current values.
17387 * * `$onDestroy()` - Called on a controller when its containing scope is destroyed. Use this hook for releasing
17388 *   external resources, watches and event handlers. Note that components have their `$onDestroy()` hooks called in
17389 *   the same order as the `$scope.$broadcast` events are triggered, which is top down. This means that parent
17390 *   components will have their `$onDestroy()` hook called before child components.
17391 * * `$postLink()` - Called after this controller's element and its children have been linked. Similar to the post-link
17392 *   function this hook can be used to set up DOM event handlers and do direct DOM manipulation.
17393 *   Note that child elements that contain `templateUrl` directives will not have been compiled and linked since
17394 *   they are waiting for their template to load asynchronously and their own compilation and linking has been
17395 *   suspended until that occurs.
17396 *
17397 * #### Comparison with Angular 2 life-cycle hooks
17398 * Angular 2 also uses life-cycle hooks for its components. While the Angular 1 life-cycle hooks are similar there are
17399 * some differences that you should be aware of, especially when it comes to moving your co
17399de from Angular 1 to Angular 2:
17400 *
17401 * * Angular 1 hooks are prefixed with `$`, such as `$onInit`. Angular 2 hooks are prefixed with `ng`, such as `ngOnInit`.
17402 * * Angular 1 hooks can be defined on the controller prototype or added to the controller inside its constructor.
17403 *   In Angular 2 you can only define hooks on the prototype of the Component class.
17404 * * Due to the differences in change-detection, you may get many more calls to `$doCheck` in Angular 1 than you would to
17405 *   `ngDoCheck` in Angular 2
17406 * * Changes to the model inside `$doCheck` will trigger new turns of the digest loop, which will cause the changes to be
17407 *   propagated throughout the application.
17408 *   Angular 2 does not allow the `ngDoCheck` hook to trigger a change outside of the component. It will either throw an
17409 *   error or do nothing depending upon the state of `enableProdMode()`.
17410 *
17411 * #### Life-cycle hook examples
17412 *
17413 * This example shows how you can check for mutations to a Date object even though the identity of the object
17414 * has not changed.
17415 *
17416 * <example name="doCheckDateExample" module="do-check-module">
17417 *   <file name="app.js">
17418 *     angular.module('do-check-module', [])
17419 *       .component('app', {
17420 *         template:
17421 *           'Month: <input ng-model="$ctrl.month" ng-change="$ctrl.updateDate()">' +
17422 *           'Date: {{ $ctrl.date }}' +
17423 *           '<test date="$ctrl.date"></test>',
17424 *         controller: function() {
17425 *           this.date = new Date();
17426 *           this.month = this.date.getMonth();
17427 *           this.updateDate = function() {
17428 *             this.date.setMonth(this.month);
17429 *           };
17430 *         }
17431 *       })
17432 *       .component('test', {
17433 *         bindings: { date: '<' },
17434 *         template:
17435 *           '<pre>{{ $ctrl.log | json }}</pre>',
17436 *         controller: function() {
17437 *           var previousValue;
17438 *           this.log = [];
17439 *           this.$doCheck = function() {
17440 *             var currentValue = this.date && this.date.valueOf();
17441 *             if (previousValue !== currentValue) {
17442 *               this.log.push('doCheck: date mutated: ' + this.date);
17443 *               previousValue = currentValue;
17444 *             }
17445 *           };
17446 *         }
17447 *       });
17448 *   </file>
17449 *   <file name="index.html">
17450 *     <app></app>
17451 *   </file>
17452 * </example>
17453 *
17454 * This example show how you might use `$doCheck` to trigger changes in your component's input
17454s even if the
17455 * actual identity of the component doesn't change. (Be aware that cloning and deep equality checks on large
17456 * arrays or objects can have a negative impact on your application performance)
17457 *
17458 * <example name="doCheckArrayExample" module="do-check-module">
17459 *   <file name="index.html">
17460 *     <div ng-init="items = []">
17461 *       <button ng-click="items.push(items.length)">Add Item</button>
17462 *       <button ng-click="items = []">Reset Items</button>
17463 *       <pre>{{ items }}</pre>
17464 *       <test items="items"></test>
17465 *     </div>
17466 *   </file>
17467 *   <file name="app.js">
17468 *      angular.module('do-check-module', [])
17469 *        .component('test', {
17470 *          bindings: { items: '<' },
17471 *          template:
17472 *            '<pre>{{ $ctrl.log | json }}</pre>',
17473 *          controller: function() {
17474 *            this.log = [];
17475 *
17476 *            this.$doCheck = function() {
17477 *              if (this.items_ref !== this.items) {
17478 *                this.log.push('doCheck: items changed');
17479 *                this.items_ref = this.items;
17480 *              }
17481 *              if (!angular.equals(this.items_clone, this.items)) {
17482 *                this.log.push('doCheck: items mutated');
17483 *                this.items_clone = angular.copy(this.items);
17484 *              }
17485 *            };
17486 *          }
17487 *        });
17488 *   </file>
17489 * </example>
17490 *
17491 *
17492 * ### Directive Definition Object
17493 *
17494 * The directive definition object provides instructions to the {@link ng.$compile
17495 * compiler}. The attributes are:
17496 *
17497 * #### `multiElement`
17498 * When this property is set to true (default is `false`), the HTML compiler will collect DOM nodes between
17499 * nodes with the attributes `directive-name-start` and `directive-name-end`, and group them
17500 * together as the directive elements. It is recommended that this feature be used on directives
17501 * which are not strictly behavioral (such as {@link ngClick}), and which
17502 * do not manipulate or replace child nodes (such as {@link ngInclude}).
17503 *
17504 * #### `priority`
17505 * When there are multiple directives defined on a single DOM element, sometimes it
17506 * is necessary to specify the order in which the directives are applied. The `priority` is used
17507 * to sort the directives before their `compile` functions get called. Priority is defined as a
17508 * number. Directives with greater numerical `priority` are compiled first. Pre-link functions
17509 * are also run in priority order, but post-link functions are run in reverse order. The order
17510 * of directives with the same priority is undefined. The default priority is `0`.
17511 *
17512 * #### `terminal`
17513 * If set to true then the current `priority` will be the last set of directives
17514 * which will execute (any directives at the current priority will still execute
17515 * as the order of execution on same `priority` is undefined). Note that expressions
17516 * and other directives used in the directive's template will also be excluded from execution.
17517 *
17518 * #### `scope`
17519 * The scope property can be `false`, `true`, or an object:
17520 *
17521 * * **`false` (default):** No scope will be created for the directive. The directive will use its
17522 * parent's scope.
17523 *
17524 * * **`true`:** A new child scope that prototypically inherits from its parent will be created for
17525 * the directive's element. If multiple directives on the same element request a new scope,
17526 * only one new scope is created.
17527 *
17528 * * **`{...}` (an object hash):** A new "isolate" scope is created for the directive's template.
17529 * The 'isolate' scope differs from normal scope in that it does not prototypically
17530 * inherit from its parent scope. This is useful when creating reusable components, which should not
17531 * accidentally read or modify data in the parent scope. Note that an isolate scope
17532 * directive without a `template` or `templateUrl` will not apply the isolate scope
17533 * to its children elements.
17534 *
17535 * The 'isolate' scope object hash defines a set of local scope properties derived from attributes on the
17536 * directive's element. These local properties are useful for aliasing values for templates. The keys in
17537 * the object hash map to the name of the property on the isolate scope; the values define how the property
17538 * is bound to the parent scope, via matching attributes on the directive's element:
17539 *
17540 * * `@` or `@attr` - bind a local scope property to the value of DOM attribute. The result is
17541 *   always a string since DOM attributes are strings. If no `attr` name is specified then the
17542 *   attribute name is assumed to be the same as the local name. Given `<my-component
17543 *   my-attr="hello {{name}}">` and the isolate scope definition `scope: { localName:'@myAttr' }`,
17544 *   the directive's scope property `localName` will reflect the interpolated value of `hello
17545 *   {{name}}`. As the `name` attribute changes so will the `localName` property on the directive's
17546 *   scope. The `name` is read from the parent scope (not the directive's scope).
17547 *
17548 * * `=` or `=attr` - set up a bidirectional binding between a local scope property and an expression
17549 *   passed via the attribute `attr`. The expression is evaluated in the context of the parent scope.
17550 *   If no `attr` name is specified then the attribute name is assumed to be the same as the local
17551 *   name. Given `<my-component my-attr="parentModel">` and the isolate scope definition `scope: {
17552 *   localModel: '=myAttr' }`, the property `localModel` on the directive's scope will reflect the
17553 *   value of `parentModel` on the parent scope. Changes to `parentModel` will be reflected in
17554 *   `localModel` and vice versa. Optional attributes should be marked as such with a question mark:
17555 *   `=?` or `=?attr`. If the binding expression is non-assignable, or if the attribute isn't
17556 *   optional and doesn't exist, an exception ({@link error/$compile/nonassign `$compile:nonassign`})
17557 *   will be thrown upon discovering changes to the local value, since it will be impossible to sync
17558 *   them back to the parent scope. By default, the {@link ng.$rootScope.Scope#$watch `$watch`}
17559 *   method is used for tracking changes, and the equality check is based on object identity.
17560 *   However, if an object literal or an array literal is passed as the binding expression, the
17561 *   equality check is done by value (using the {@link angular.equals} function). It's also possible
17562 *   to watch the evaluated value shallowly with {@link ng.$rootScope.Scope#$watchCollection
17563 *   `$watchCollection`}: use `=*` or `=*attr` (`=*?` or `=*?attr` if the attribute is optional).
17564 *
17565  * * `<` or `<attr` - set up a one-way (one-directional) binding between a local scope property and an
17566 *   expression passed via the attribute `attr`. The expression is evaluated in the context of the
17567 *   parent scope. If no `attr` name is specified then the attribute name is assumed to be the same as the
17568 *   local name. You can also make the binding optional by adding `?`: `<?` or `<?attr`.
17569 *
17570 *   For example, given `<my-component my-attr="parentModel">` and directive definition of
17571 *   `scope: { localModel:'<myAttr' }`, then the isolated scope property `localModel` will reflect the
17572 *   value of `parentModel` on the parent scope. Any changes to `parentModel` will be reflected
17573 *   in `localModel`, but changes in `localModel` will not reflect in `parentModel`. There are however
17574 *   two caveats:
17575 *     1. one-way binding does not copy the value from the parent to the isolate scope, it simply
17576 *     sets the same value. That means if your bound value is an object, changes to its properties
17577 *     in the isolated scope will be reflected in the parent scope (because both reference the same object).
17578 *     2. one-way binding watches changes to the **identity** of the parent value. That means the
17579 *     {@link ng.$rootScope.Scope#$watch `$watch`} on the parent value only fires if the reference
17580 *     to the value has changed. In most cases, this should not be of concern, but can be important
17581 *     to know if you one-way bind to an object, and then replace that object in the isolated scope.
17582 *     If you now change a property of the object in your parent scope, the change will not be
17583 *     propagated to the isolated scope, because the identity of the object on the parent scope
17584 *     has not changed. Instead you must assign a new object.
17585 *
17586 *   One-way binding is useful if you do not plan to propagate changes to your isolated scope bindings
17587 *   back to the parent. However, it does not make this completely impossible.
17588 *
17589 * * `&` or `&attr` - provides a way to execute an expression in the context of the parent scope. If
17590 *   no `attr` name is specified then the attribute name is assumed to be the same as the local name.
17591 *   Given `<my-component my-attr="count = count + value">` and the isolate scope definition `scope: {
17592 *   localFn:'&myAttr' }`, the isolate scope property `localFn` will point to a function wrapper for
17593 *   the `count = count + value` expression. Often it's desirable to pass data from the isolated scope
17594 *   via an expression to the parent scope. This can be done by passing a map of local variable names
17595 *   and values into the expression wrapper fn. For example, if the expression is `increment(amount)`
17596 *   then we can specify the amount value by calling the `localFn` as `localFn({amount: 22})`.
17597 *
17598 * In general it's possible to apply more than one directive to one element, but there might be limitations
17599 * depending on the type of scope required by the directives. The following points will help explain these limitations.
17600 * For simplicity only two directives are taken into account, but it is also applicable for several directives:
17601 *
17602 * * **no scope** + **no scope** => Two directives which don't require their own scope will use their parent's scope
17603 * * **child scope** + **no scope** =>  Both directives will share one single child scope
17604 * * **child scope** + **child scope** =>  Both directives will share one single child scope
17605 * * **isolated scope** + **no scope** =>  The isolated directive will use it's own created isolated scope. The other directive will use
17606 * its parent's scope
17607 * * **isolated scope** + **child scope** =>  **Won't work!** Only one scope can be related to one element. Therefore these directives cannot
17608 * be applied to the same element.
17609 * * **isolated scope** + **isolated scope**  =>  **Won't work!** Only one scope can be related to one element. Therefore these directives
17610 * cannot be applied to the same element.
17611 *
17612 *
17613 * #### `bindToController`
17614 * This property is used to bind scope properties directly to the controller. It can be either
17615 * `true` or an object hash with the same format as the `scope` property.
17616 *
17617 * When an isolate scope is used for a directive (see above), `bindToController: true` will
17618 * allow a component to have its properties bound to the controller, rather than to scope.
17619 *
17620 * After the controller is instantiated, the initial values of the isolate scope bindings will be bound to the controller
17621 * properties. You can access these bindings once they have been initialized by providing a controller method called
17622 * `$onInit`, which is called after all the controllers on an element have been constructed and had their bindings
17623 * initialized.
17624 *
17625 * <div class="alert alert-warning">
17626 * **Deprecation warning:** although bindings for non-ES6 class controllers are currently
17627 * bound to `this` before the controller constructor is called, this use is now deprecated. Please place initialization
17628 * code that relies upon bindings inside a `$onInit` method on the controller, instead.
17629 * </div>
17630 *
17631 * It is also possible to set `bindToController` to an object hash with the same format as the `scope` property.
17632 * This will set up the scope bindings to the controller directly. Note that `scope` can still be used
17633 * to define which kind of scope is created. By default, no scope is created. Use `scope: {}` to create an isolate
17634 * scope (useful for component directives).
17635 *
17636 * If both `bindToController` and `scope` are defined and have object hashes, `bindToController` overrides `scope`.
17637 *
17638 *
17639 * #### `controller`
17640 * Controller constructor function. The controller is instantiated before the
17641 * pre-linking phase and can be accessed by other directives (see
17642 * `require` attribute). This allows the directives to communicate with each other and augment
17643 * each other's behavior. The controller is injectable (and supports bracket notation) with the following locals:
17644 *
17645 * * `$scope` - Current scope associated with the element
17646 * * `$element` - Current element
17647 * * `$attrs` - Current attributes object for the element
17648 * * `$transclude` - A transclude linking function pre-bound to the correct transclusion scope:
17649 *   `function([scope], cloneLinkingFn, futureParentElement, slotName)`:
17650 *    * `scope`: (optional) override the scope.
17651 *    * `cloneLinkingFn`: (optional) argument to create clones of the original transcluded content.
17652 *    * `futureParentElement` (optional):
17653 *        * defines the parent to which the `cloneLinkingFn` will add the cloned elements.
17654 *        * default: `$element.parent()` resp. `$element` for `transclude:'element'` resp. `transclude:true`.
17655 *        * only needed for transcludes that are allowed to contain non html elements (e.g. SVG elements)
17656 *          and when the `cloneLinkingFn` is passed,
17657 *          as those elements need to created and cloned in a special way when they are defined outside their
17658 *          usual containers (e.g. like `<svg>`).
17659 *        * See also the `directive.templateNamespace` property.
17660 *    * `slotName`: (optional) the name of the slot to transclude. If falsy (e.g. `null`, `undefined` or `''`)
17661 *      then the default transclusion is provided.
17662 *    The `$transclude` function also has a method on it, `$transclude.isSlotFilled(slotName)`, which returns
17663 *    `true` if the specified slot contains content (i.e. one or more DOM nodes).
17664 *
17665 * #### `require`
17666 * Require another directive and inject its controller as the fourth argument to the linking function. The
17667 * `require` property can be a string, an array or an object:
17668 * * a **string** containing the name of the directive to pass to the linking function
17669 * * an **array** containing the names of directives to pass to the linking function. The argument passed to the
17670 * linking function will be an array of controllers in the same order as the names in the `require` property
17671 * * an **object** whose property values are the names of the directives to pass to the linking function. The argument
17672 * passed to the linking function will also be an object with matching keys, whose values will hold the corresponding
17673 * controllers.
17674 *
17675 * If the `require` property is an object and `bindToController` is truthy, then the required controllers are
17676 * bound to the controller using the keys of the `require` property. This binding occurs after all the controllers
17677 * have been constructed but before `$onInit` is called.
17678 * If the name of the required controller is the same as the local name (the key), the name can be
17679 * omitted. For example, `{parentDir: '^^'}` is equivalent to `{parentDir: '^^parentDir'}`.
17680 * See the {@link $compileProvider#component} helper for an example of how this can be used.
17681 * If no such required directive(s) can be found, or if the directive does not have a controller, then an error is
17682 * raised (unless no link function is specified and the required controllers are not being bound to the directive
17683 * controller, in which case error checking is skipped). The name can be prefixed with:
17684 *
17685 * * (no prefix) - Locate the required controller on the current element. Throw an error if not found.
17686 * * `?` - Attempt to locate the required controller or pass `null` to the `link` fn if not found.
17687 * * `^` - Locate the required controller by searching the element and its parents. Throw an error if not found.
17688 * * `^^` - Locate the required controller by searching the element's parents. Throw an error if not found.
17689 * * `?^` - Attempt to locate the required controller by searching the element and its parents or pass
17690 *   `null` to the `link` fn if not found.
17691 * * `?^^` - Attempt to locate the required controller by searching the element's parents, or pass
17692 *   `null` to the `link` fn if not found.
17693 *
17694 *
17695 * #### `controllerAs`
17696 * Identifier name for a reference to the controller in the directive's scope.
17697 * This allows the controller to be referenced from the directive template. This is especially
17698 * useful when a directive is used as component, i.e. with an `isolate` scope. It's also possible
17699 * to use it in a directive without an `isolate` / `new` scope, but you need to be aware that the
17700 * `controllerAs` reference might overwrite a property that already exists on the parent scope.
17701 *
17702 *
17703 * #### `restrict`
17704 * String of subset of `EACM` which restricts the directive to a specific directive
17705 * declaration style. If omitted, the defaults (elements and attributes) are used.
17706 *
17707 * * `E` - Element name (default): `<my-directive></my-directive>`
17708 * * `A` - Attribute (default): `<div my-directive="exp"></div>`
17709 * * `C` - Class: `<div class="my-directive: exp;"></div>`
17710 * * `M` - Comment: `<!-- directive: my-directive exp -->`
17711 *
17712 *
17713 * #### `templateNamespace`
17714 * String representing the document type used by the markup in the template.
17715 * AngularJS needs this information as those elements need to be created and cloned
17716 * in a special way when they are defined outside their usual containers like `<svg>` and `<math>`.
17717 *
17718 * * `html` - All root nodes in the template are HTML. Root nodes may also be
17719 *   top-level elements such as `<svg>` or `<math>`.
17720 * * `svg` - The root nodes in the template are SVG elements (excluding `<math>`).
17721 * * `math` - The root nodes in the template are MathML elements (excluding `<svg>`).
17722 *
17723 * If no `templateNamespace` is specified, then the namespace is considered to be `html`.
17724 *
17725 * #### `template`
17726 * HTML markup that may:
17727 * * Replace the contents of the directive's element (default).
17728 * * Replace the directive's element itself (if `replace` is true - DEPRECATED).
17729 * * Wrap the contents of the directive's element (if `transclude` is true).
17730 *
17731 * Value may be:
17732 *
17733 * * A string. For example `<div red-on-hover>{{delete_str}}</div>`.
17734 * * A function which takes two arguments `tElement` and `tAttrs` (described 
17734in the `compile`
17735 *   function api below) and returns a string value.
17736 *
17737 *
17738 * #### `templateUrl`
17739 * This is similar to `template` but the template is loaded from the specified URL, asynchronously.
17740 *
17741 * Because template loading is asynchronous the compiler will suspend compilation of directives on that element
17742 * for later when the template has been resolved.  In the meantime it will continue to compile and link
17743 * sibling and parent elements as though this element had not contained any directives.
17744 *
17745 * The compiler does not suspend the entire compilation to wait for templates to be loaded because this
17746 * would result in the whole app "stalling" until all templates are loaded asynchronously - even in the
17747 * case when only one deeply nested directive has `templateUrl`.
17748 *
17749 * Template loading is asynchronous even if the template has been preloaded into the {@link $templateCache}
17750 *
17751 * You can specify `templateUrl` as a string representing the URL or as a function which takes two
17752 * arguments `tElement` and `tAttrs` (described in the `compile` function api below) and returns
17753 * a string value representing the url.  In either case, the template URL is passed through {@link
17754 * $sce#getTrustedResourceUrl $sce.getTrustedResourceUrl}.
17755 *
17756 *
17757 * #### `replace` ([*DEPRECATED*!], will be removed in next major release - i.e. v2.0)
17758 * specify what the template should replace. Defaults to `false`.
17759 *
17760 * * `true` - the template will replace the directive's element.
17761 * * `false` - the template will replace the contents of the directive's element.
17762 *
17763 * The replacement process migrates all of the attributes / classes from the old element to the new
17764 * one. See the {@link guide/directive#template-expanding-directive
17765 * Directives Guide} for an example.
17766 *
17767 * There are very few scenarios where element replacement is required for the application function,
17768 * the main one being reusable custom components that are used within SVG contexts
17769 * (because SVG doesn't work with custom elements in the DOM tree).
17770 *
17771 * #### `transclude`
17772 * Extract the contents of the element where the directive appears and make it available to the directive.
17773 * The contents are compiled and provided to the directive as a **transclusion function**. See the
17774 * {@link $compile#transclusion Transclusion} section below.
17775 *
17776 *
17777 * #### `compile`
17778 *
17779 * ```js
17780 *   function compile(tElement, tAttrs, transclude) { ... }
17781 * ```
17782 *
17783 * The compile function deals with transforming the template DOM. Since most directives do not do
17784 * template transformation, it is not used often. The compile function takes the following arguments:
17785 *
17786 *   * `tElement` - template element - The element where the directive has been declared. It is
17787 *     safe to do template transformation on the element and child elements only.
17788 *
17789 *   * `tAttrs` - template attributes - Normalized list of attributes declared on this element shared
17790 *     between all directive compile functions.
17791 *
17792 *   * `transclude` -  [*DEPRECATED*!] A transclude linking function: `function(scope, cloneLinkingFn)`
17793 *
17794 * <div class="alert alert-warning">
17795 * **Note:** The template instance and the link instance may be different objects if the template has
17796 * been cloned. For this reason it is **not** safe to do anything other than DOM transformations that
17797 * apply to all cloned DOM nodes within the compile function. Specifically, DOM listener registration
17798 * should be done in a linking function rather than in a compile function.
17799 * </div>
17800
17801 * <div class="alert alert-warning">
17802 * **Note:** The compile function cannot handle directives that recursively use themselves in their
17803 * own templates or compile functions. Compiling these directives results in an infinite loop and
17804 * stack overflow errors.
17805 *
17806 * This can be avoided by manually using $compile
vendor: 5,458 bytes, lines 17806-17910
17806 in the postLink function to imperatively compile
17807 * a directive's template instead of relying on automatic template compilation via `template` or
17808 * `templateUrl` declaration or manual compilation inside the compile function.
17809 * </div>
17810 *
17811 * <div class="alert alert-danger">
17812 * **Note:** The `transclude` function that is passed to the compile function is deprecated, as it
17813 *   e.g. does not know about the right outer scope. Please use the transclude function that is passed
17814 *   to the link function instead.
17815 * </div>
17816
17817 * A compile function can have a return value which can be either a function or an object.
17818 *
17819 * * returning a (post-link) function - is equivalent to registering the linking function via the
17820 *   `link` property of the config object when the compile function is empty.
17821 *
17822 * * returning an object with function(s) registered via `pre` and `post` properties - allows you to
17823 *   control when a linking function should be called during the linking phase. See info about
17824 *   pre-linking and post-linking functions below.
17825 *
17826 *
17827 * #### `link`
17828 * This property is used only if the `compile` property is not defined.
17829 *
17830 * ```js
17831 *   function link(scope, iElement, iAttrs, controller, transcludeFn) { ... }
17832 * ```
17833 *
17834 * The link function is responsible for registering DOM listeners as well as updating the DOM. It is
17835 * executed after the template has been cloned. This is where most of the directive logic will be
17836 * put.
17837 *
17838 *   * `scope` - {@link ng.$rootScope.Scope Scope} - The scope to be used by the
17839 *     directive for registering {@link ng.$rootScope.Scope#$watch watches}.
17840 *
17841 *   * `iElement` - instance element - The element where the directive is to be used. It is safe to
17842 *     manipulate the children of the element only in `postLink` function since the children have
17843 *     already been linked.
17844 *
17845 *   * `iAttrs` - instance attributes - Normalized list of attributes declared on this element shared
17846 *     between all directive linking functions.
17847 *
17848 *   * `controller` - the directive's required controller instance(s) - Instances are shared
17849 *     among all directives, which allows the directives to use the controllers as a communication
17850 *     channel. The exact value depends on the directive's `require` property:
17851 *       * no controller(s) required: the directive's own controller, or `undefined` if it doesn't have one
17852 *       * `string`: the controller instance
17853 *       * `array`: array of controller instances
17854 *
17855 *     If a required controller cannot be found, and it is optional, the instance is `null`,
17856 *     otherwise the {@link error:$compile:ctreq Missing Required Controller} error is thrown.
17857 *
17858 *     Note that you can also require the directive's own controller - it will be made available like
17859 *     any other controller.
17860 *
17861 *   * `transcludeFn` - A transclude linking function pre-bound to the correct transclusion scope.
17862 *     This is the same as the `$transclude` parameter of directive controllers,
17863 *     see {@link ng.$compile#-controller- the controller section for details}.
17864 *     `function([scope], cloneLinkingFn, futureParentElement)`.
17865 *
17866 * #### Pre-linking function
17867 *
17868 * Executed before the child elements are linked. Not safe to do DOM transformation since the
17869 * compiler linking function will fail to locate the correct elements for linking.
17870 *
17871 * #### Post-linking function
17872 *
17873 * Executed after the child elements are linked.
17874 *
17875 * Note that child elements that contain `templateUrl` directives will not have been compiled
17876 * and linked since they are waiting for their template to load asynchronously and their own
17877 * compilation and linking has been suspended until that occurs.
17878 *
17879 * It is safe to do DOM transformation in the post-linking function on elements that are not waiting
17880 * for their async templates to be resolved.
17881 *
17882 *
17883 * ### Transclusion
17884 *
17885 * Transclusion is the process of extracting a collection of DOM elements from one part of the DOM and
17886 * copying them to another part of the DOM, while maintaining their connection to the original AngularJS
17887 * scope from where they were taken.
17888 *
17889 * Transclusion is used (often with {@link ngTransclude}) to insert the
17890 * original contents of a directive's element into a specified place in the template of the directive.
17891 * The benefit of transclusion, over simply moving the DOM elements manually, is that the transcluded
17892 * content has access to the properties on the scope from which it was taken, even if the directive
17893 * has isolated scope.
17894 * See the {@link guide/directive#creating-a-directive-that-wraps-other-elements Directives Guide}.
17895 *
17896 * This makes it possible for the widget to have private state for its template, while the transcluded
17897 * content has access to its originating scope.
17898 *
17899 * <div class="alert alert-warning">
17900 * **Note:** When testing an element transclude directive you must not place the directive at the root of the
17901 * DOM fragment that is being compiled. See {@link guide/unit-testing#testing-transclusion-directives
17902 * Testing Transclusion Directives}.
17903 * </div>
17904 *
17905 * There are three kinds of transclusion depending upon whether you want to transclude just the contents of the
17906 * directive's element, the entire element or multiple parts of the element contents:
17907 *
17908 * * `true` - transclude the content (i.e. the child nodes) of the directive's element.
17909 * * `'element'` - transclude the whole of the directive's element including any directives on this
17910 *   element that 
17910defined at a lower priority than this directive. When used, the `template`
17911 *   property is ignored.
17912 * * **`{...}` (an object hash):** - map elements of the content onto transclusion "slots" in the template.
17913 *
17914 * **Mult-slot transclusion** is declared by providing an object for the `transclude` property.
17915 *
17916 * This object is a map where the keys are the name of the slot to fill and the value is an element selector
17917 * used to match the HTML to the slot. The element selector should be in normalized form (e.g. `myElement`)
17918 * and will match the standard element variants (e.g. `my-element`, `my:element`, `data-my-element`, etc).
17919 *
17920 * For further information check out the guide on {@link guide/directive#matching-directives Matching Directives}
17921 *
17922 * If the element selector is prefixed with a `?` then that slot is optional.
17923 *
17924 * For example, the transclude object `{ slotA: '?myCustomElement' }` maps `<my-custom-element>` elements to
17925 * the `slotA` slot, which can be accessed via the `$transclude` function or via the {@link ngTransclude} directive.
17926 *
17927 * Slots that are not marked as optional (`?`) will trigger a compile time error if there are no matching elements
17928 * in the transclude content. If you wish to know if an optional slot was filled with content, then you can call
17929 * `$transclude.isSlotFilled(slotName)` on the transclude function passed to the directive's link function and
17930 * injectable into the directive's controller.
17931 *
17932 *
17933 * #### Transclusion Functions
17934 *
17935 * When a directive requests transclusion, the compiler extracts its contents and provides a **transclusion
17936 * function** to the directive's `link` function and `controller`. This transclusion function is a special
17937 * **linking function** that will return the compiled contents linked to a new transclusion scope.
17938 *
17939 * <div class="alert alert-info">
17940 * If you are just using {@link ngTransclude} then you don't need to worry about this function, since
17941 * ngTransclude will deal with it for us.
17942 * </div>
17943 *
17944 * If you want to manually control the insertion and removal of the transcluded content in your directive
17945 * then you must use this transclude function. When you call a transclude function it returns a a jqLite/JQuery
17946 * object that contains the compiled DOM, which is linked to the correct transclusion scope.
17947 *
17948 * When you call a transclusion function you can pass in a **clone attach function**. This function accepts
17949 * two parameters, `function(clone, scope) { ... }`, where the `clone` is a fresh compiled copy of your transcluded
17950 * content and the `scope` is the newly created transclusion scope, which the clone will be linked to.
17951 *
17952 * <div class="alert alert-info">
17953 * **Best Practice**: Always provide a `cloneFn` (clone attach function) when you call a transclude function
17954 * since you then get a fresh clone of the original DOM and also have access to the new transclusion scope.
17955 * </div>
17956 *
17957 * It is normal practice to attach your transcluded content (`clone`) to the DOM inside your **clone
17958 * attach function**:
17959 *
17960 * ```js
17961 * var transcludedContent, transclusionScope;
17962 *
17963 * $transclude(function(clone, scope) {
17964 *   element.append(clone);
17965 *   transcludedContent = clone;
17966 *   transclusionScope = scope;
17967 * });
17968 * ```
17969 *
17970 * Later, if you want to remove the transcluded content from your DOM then you should also destroy the
17971 * associated transclusion scope:
17972 *
17973 * ```js
17974 * transcludedContent.remove();
17975 * transclusionScope.$destroy();
17976 * ```
17977 *
17978 * <div class="alert alert-info">
17979 * **Best Practice**: if you intend to add and remove transcluded content manually in your directive
17980 * (by calling the transclude function to get the DOM and calling `element.remove()` to remove it),
17981 * then you are also responsible for calling `$destroy` on the transclusion scope.
17982 * </div>
17983 *
17984 * The built-in DOM manipulation directives, such as {@link ngIf}, {@link ngSwitch} and {@link ngRepeat}
17985 * automatically destroy their transcluded clones as necessary so you do not need to worry about this if
17986 * you are simply using {@link ngTransclude} to inject the transclusion into your directive.
17987 *
17988 *
17989 * #### Transclusion Scopes
17990 *
17991 * When you call a transclude function it returns a DOM fragment that is pre-bound to a **transclusion
17992 * scope**. This scope is special, in that it is a child of the directive's scope (and so gets destroyed
17993 * when the directive's scope gets destroyed) but it inherits the properties of the scope from which it
17994 * was taken.
17995 *
17996 * For example consider a directive that uses transclusion and isolated scope. The DOM hierarchy might look
17997 * like this:
17998 *
17999 * ```html
18000 * <div ng-app>
18001 *   <div isolate>
18002 *     <div transclusion>
18003 *     </div>
18004 *   </div>
18005 * </div>
18006 * ```
18007 *
18008 * The `$parent` scope hierarchy will look like this:
18009 *
18010   ```
18011   - $rootScope
18012     - isolate
18013       - transclusion
18014   ```
18015 *
18016 * but the scopes will inherit prototypically from different scopes to their `$parent`.
18017 *
18018   ```
18019   - $rootScope
18020     - transclusion
18021   - isolate
18022   ```
18023 *
18024 *
18025 * ### Attributes
18026 *
18027 * The {@link ng.$compile.directive.Attributes Attributes} object - passed as a parameter in the
18028 * `link()` or `compile()` functions. It has a variety of uses.
18029 *
18030 * * *Accessing normalized attribute names:* Directives like 'ngBind' can be expressed in many ways:
18031 *   'ng:bind', `data-ng-bind`, or 'x-ng-bind'. The attributes object allows for normalized access
18032 *   to the attributes.
18033 *
18034 * * *Directive inter-communication:* All directives share the same instance of the attributes
18035 *   object which allows the directives to use the attributes object as inter directive
18036 *   communication.
18037 *
18038 * * *Supports interpolation:* Interpolation attributes are assigned to the attribute object
18039 *   allowing other directives to read the interpolated value.
18040 *
18041 * * *Observing interpolated attributes:* Use `$observe` to observe the value changes of attributes
18042 *   that contain interpolation (e.g. `src="{{bar}}"`). Not only is this very efficient but it's also
18043 *   the only way to easily get the actual value because during the linking phase the interpolation
18044 *   hasn't been evaluated yet and so the value is at this time set to `undefined`.
18045 *
18046 * ```js
18047 * function linkingFn(scope, elm, attrs, ctrl) {
18048 *   // get the attribute value
18049 *   console.log(attrs.ngModel);
18050 *
18051 *   // change the attribute
18052 *   attrs.$set('ngModel', 'new value');
18053 *
18054 *   // observe changes to interpolated attribute
18055 *   attrs.$observe('ngModel', function(value) {
18056 *     console.log('ngModel has changed value to ' + value);
18057 *   });
18058 * }
18059 * ```
18060 *
18061 * ## Example
18062 *
18063 * <div class="alert alert-warning">
18064 * **Note**: Typically directives are registered with `module.directive`. The example below is
18065 * to illustrate how `$compile` works.
18066 * </div>
18067 *
18068 <example module="compileExample" name="compile">
18069   <file name="index.html">
18070    <script>
18071      angular.module('compileExample', [], function($compileProvider) {
18072        // configure new 'compile' directive by passing a directive
18073        // factory function. The factory function injects the '$compile'
18074        $compileProvider.directive('compile', function($compile) {
18075          // directive factory creates a link function
18076          return function(scope, element, attrs) {
18077            scope.$watch(
18078              function(scope) {
18079                 // watch the 'compile' expression for changes
18080                return scope.$eval(attrs.compile);
18081              },
18082              function(value) {
18083                // when the 'compile' expression changes
18084                // assign it into the current DOM
18085                element.html(value);
18086
18087                // compile the new DOM and link it to the current
18088                // scope.
18089                // NOTE: we only compile .childNodes so that
18090                // we don't get into infinite loop compiling ourselves
18091                $compile(element.contents())(scope);
18092              }
18093            );
18094          };
18095        });
18096      })
18097      .controller('GreeterController', ['$scope', function($scope) {
18098        $scope.name = 'Angular';
18099        $scope.html = 'Hello {{name}}';
18100      }]);
18101    </script>
18102    <div ng-controller="GreeterController">
18103      <input ng-model="name"> <br/>
18104      <textarea ng-model="html"></textarea> <br/>
18105      <div compile="html"></div>
18106    </div>
18107   </file>
18108   <file name="protractor.js" type="protractor">
18109     it('should auto compile', function() {
18110       var textarea = $('textarea');
18111       var output = $('div[compile]');
18112       // The initial state reads 'Hello Angular'.
18113       expect(output.getText()).toBe('Hello Angular');
18114       textarea.clear();
18115       textarea.sendKeys('{{name}}!');
18116       expect(output.getText()).toBe('Angular!');
18117     });
18118   </file>
18119 </example>
18120
18121 *
18122 *
18123 * @param {string|DOMElement} element Element or HTML string to compile into a template function.
18124 * @param {function(angular.Scope, cloneAttachFn=)} transclude function available to directives - DEPRECATED.
18125 *
18126 * <div class="alert alert-danger">
18127 * **Note:** Passing a `transclude` function to the $compile function is deprecated, as it
18128 *   e.g. will not use the right outer scope. Please pass the transclude function as a
18129 *   `parentBoundTranscludeFn` to the link function instead.
18130 * </div>
18131 *
18132 * @param {number} maxPriority only apply directives lower than given priority (Only effects the
18133 *                 root element(s), not their children)
18134 * @returns {function(scope, cloneAttachFn=, options=)} a link function which is used to bind template
18135 * (a DOM element/tree) to a scope. Where:
18136 *
18137 *  * `scope` - A {@link ng.$rootScope.Scope Scope} to bind to.
18138 *  * `cloneAttachFn` - If `cloneAttachFn` is provided, then the link function will clone the
18139 *  `template` and call the `cloneAttachFn` function allowing the caller to attach the
18140 *  cloned elements to the DOM document at the appropriate place. The `cloneAttachFn` is
18141 *  called as: <br/> `cloneAttachFn(clonedElement, scope)` where:
18142 *
18143 *      * `clonedElement` - is a clone of the original `element` passed into the compiler.
18144 *      * `scope` - is the current scope with which the linking function is working with.
18145 *
18146 *  * `options` - An optional object hash with linking options. If `options` is provided, then the following
18147 *  keys may be used to control linking behavior:
18148 *
18149 *      * `parentBoundTranscludeFn` - the transclude function made available to
18150 *        directives; if given, it will be passed through to the link functions of
18151 *        directives found in `element` during compilation.
18152 *      * `transcludeControllers` - an object hash with keys that map controller names
18153 *        to a hash with the key `instance`, which maps to the controller instance;
18154 *        if given, it will make the controllers available to directives on the compileNode:
18155 *        ```
18156 *        {
18157 *          parent: {
18158 *            instance: parentControllerInstance
18159 *          }
18160 *        }
18161 *        ```
18162 *      * `futureParentElement` - defines the parent to which the `cloneAttachFn` will add
18163 *        the cloned elements; only needed for transcludes that are allowed to contain non html
18164 *        elements (e.g. SVG elements). See also the directive.controller property.
18165 *
18166 * Calling the linking function returns the element of the template. It is either the original
18167 * element passed in, or the clone of the element if the `cloneAttachFn` is provided.
18168 *
18169 * After linking the view is not updated until after a call to $digest which typically is done by
18170 * Angular automatically.
18171 *
18172 * If you need access to the bound view, there are two ways to do it:
18173 *
18174 * - If you are not asking the linking function to clone the template, create the DOM element(s)
18175 *   before you send them to the compiler and keep this reference around.
18176 *   ```js
18177 *     var element = $compile('<p>{{total}}</p>')(scope);
18178 *   ```
18179 *
18180 * - if on the other hand, you need the element to be cloned, the view reference from the original
18181 *   example would not point to the clone, but rather to the original template that was cloned. In
18182 *   this case, you can access the clone via the cloneAttachFn:
18183 *   ```js
18184 *     var templateElement = angular.element('<p>{{total}}</p>'),
18185 *         scope = ....;
18186 *
18187 *     var clonedElement = $compile(templateElement)(scope, function(clonedElement, scope) {
18188 *       //attach the clone to DOM document at the right place
18189 *     });
18190 *
18191 *     //now we have reference to the cloned DOM via `clonedElement`
18192 *   ```
18193 *
18194 *
18195 * For information on how the compiler works, see the
18196 * {@link guide/compiler Angular HTML Compiler} section of the Developer Guide.
18197 *
18198 * @knownIssue
18199 *
18200 * ### Double Compilation
18201 *
18202   Double compilation occurs when an already compiled part of the DOM gets
18203   compiled again. This is an undesired effect and can lead to misbehaving directives, performance issues,
18204   and memory leaks. Refer to the Compiler Guide {@link guide/compiler#double-compilation-and-how-to-avoid-it
18205   section on double compilation} for an in-depth explanation and ways to avoid it.
18206 *
18207 */
18208
18209var $compileMinErr = minErr('$compile');
18210
18211function UNINITIALIZED_VALUE() {}
18212var _UNINITIALIZED_VALUE = new UNINITIALIZED_VALUE();
18213
18214/**
18215 * @ngdoc provider
18216 * @name $compileProvider
18217 *
18218 * @description
18219 */
vendor: 15,193 bytes, lines 18220-18587
18220$CompileProvider.$inject = ['$provide', '$$sanitizeUriProvider'];
18221/** @this */
18222function $CompileProvider($provide, $$sanitizeUriProvider) {
18223  var hasDirectives = {},
18224      Suffix = 'Directive',
18225      COMMENT_DIRECTIVE_REGEXP = /^\s*directive:\s*([\w-]+)\s+(.*)$/,
18226      CLASS_DIRECTIVE_REGEXP = /(([\w-]+)(?::([^;]+))?;?)/,
18227      ALL_OR_NOTHING_ATTRS = makeMap('ngSrc,ngSrcset,src,srcset'),
18228      REQUIRE_PREFIX_REGEXP = /^(?:(\^\^?)?(\?)?(\^\^?)?)?/;
18229
18230  // Ref: http://developers.whatwg.org/webappapis.html#event-handler-idl-attributes
18231  // The assumption is that future DOM event attribute names will begin with
18232  // 'on' and be composed of only English letters.
18233  var EVENT_HANDLER_ATTR_REGEXP = /^(on[a-z]+|formaction)$/;
18234  var bindingCache = createMap();
18235
18236  function parseIsolateBindings(scope, directiveName, isController) {
18237    var LOCAL_REGEXP = /^\s*([@&<]|=(\*?))(\??)\s*([\w$]*)\s*$/;
18238
18239    var bindings = createMap();
18240
18241    forEach(scope, function(definition, scopeName) {
18242      if (definition in bindingCache) {
18243        bindings[scopeName] = bindingCache[definition];
18244        return;
18245      }
18246      var match = definition.match(LOCAL_REGEXP);
18247
18248      if (!match) {
18249        throw $compileMinErr('iscp',
18250            'Invalid {3} for directive \'{0}\'.' +
18251            ' Definition: {... {1}: \'{2}\' ...}',
18252            directiveName, scopeName, definition,
18253            (isController ? 'controller bindings definition' :
18254            'isolate scope definition'));
18255      }
18256
18257      bindings[scopeName] = {
18258        mode: match[1][0],
18259        collection: match[2] === '*',
18260        optional: match[3] === '?',
18261        attrName: match[4] || scopeName
18262      };
18263      if (match[4]) {
18264        bindingCache[definition] = bindings[scopeName];
18265      }
18266    });
18267
18268    return bindings;
18269  }
18270
18271  function parseDirectiveBindings(directive, directiveName) {
18272    var bindings = {
18273      isolateScope: null,
18274      bindToController: null
18275    };
18276    if (isObject(directive.scope)) {
18277      if (directive.bindToController === true) {
18278        bindings.bindToController = parseIsolateBindings(directive.scope,
18279                                                         directiveName, true);
18280        bindings.isolateScope = {};
18281      } else {
18282        bindings.isolateScope = parseIsolateBindings(directive.scope,
18283                                                     directiveName, false);
18284      }
18285    }
18286    if (isObject(directive.bindToController)) {
18287      bindings.bindToController =
18288          parseIsolateBindings(directive.bindToController, directiveName, true);
18289    }
18290    if (bindings.bindToController && !directive.controller) {
18291      // There is no controller
18292      throw $compileMinErr('noctrl',
18293            'Cannot bind to controller without directive \'{0}\'s controller.',
18294            directiveName);
18295    }
18296    return bindings;
18297  }
18298
18299  function assertValidDirectiveName(name) {
18300    var letter = name.charAt(0);
18301    if (!letter || letter !== lowercase(letter)) {
18302      throw $compileMinErr('baddir', 'Directive/Component name \'{0}\' is invalid. The first character must be a lowercase letter', name);
18303    }
18304    if (name !== name.trim()) {
18305      throw $compileMinErr('baddir',
18306            'Directive/Component name \'{0}\' is invalid. The name should not contain leading or trailing whitespaces',
18307            name);
18308    }
18309  }
18310
18311  function getDirectiveRequire(directive) {
18312    var require = directive.require || (directive.controller && directive.name);
18313
18314    if (!isArray(require) && isObject(require)) {
18315      forEach(require, function(value, key) {
18316        var match = value.match(REQUIRE_PREFIX_REGEXP);
18317        var name = value.substring(match[0].length);
18318        if (!name) require[key] = match[0] + key;
18319      });
18320    }
18321
18322    return require;
18323  }
18324
18325  function getDirectiveRestrict(restrict, name) {
18326    if (restrict && !(isString(restrict) && /[EACM]/.test(restrict))) {
18327      throw $compileMinErr('badrestrict',
18328          'Restrict property \'{0}\' of directive \'{1}\' is invalid',
18329          restrict,
18330          name);
18331    }
18332
18333    return restrict || 'EA';
18334  }
18335
18336  /**
18337   * @ngdoc method
18338   * @name $compileProvider#directive
18339   * @kind function
18340   *
18341   * @description
18342   * Register a new directive with the compiler.
18343   *
18344   * @param {string|Object} name Name of the directive in camel-case (i.e. <code>ngBind</code> which
18345   *    will match as <code>ng-bind</code>), or an object map of directives where the keys are the
18346   *    names and the values are the factories.
18347   * @param {Function|Array} directiveFactory An injectable directive factory function. See the
18348   *    {@link guide/directive directive guide} and the {@link $compile compile API} for more info.
18349   * @returns {ng.$compileProvider} Self for chaining.
18350   */
18351  this.directive = function registerDirective(name, directiveFactory) {
18352    assertArg(name, 'name');
18353    assertNotHasOwnProperty(name, 'directive');
18354    if (isString(name)) {
18355      assertValidDirectiveName(name);
18356      assertArg(directiveFactory, 'directiveFactory');
18357      if (!hasDirectives.hasOwnProperty(name)) {
18358        hasDirectives[name] = [];
18359        $provide.factory(name + Suffix, ['$injector', '$exceptionHandler',
18360          function($injector, $exceptionHandler) {
18361            var directives = [];
18362            forEach(hasDirectives[name], function(directiveFactory, index) {
18363              try {
18364                var directive = $injector.invoke(directiveFactory);
18365                if (isFunction(directive)) {
18366                  directive = { compile: valueFn(directive) };
18367                } else if (!directive.compile && directive.link) {
18368                  directive.compile = valueFn(directive.link);
18369                }
18370                directive.priority = directive.priority || 0;
18371                directive.index = index;
18372                directive.name = directive.name || name;
18373                directive.require = getDirectiveRequire(directive);
18374                directive.restrict = getDirectiveRestrict(directive.restrict, name);
18375                directive.$$moduleName = directiveFactory.$$moduleName;
18376                directives.push(directive);
18377              } catch (e) {
18378                $exceptionHandler(e);
18379              }
18380            });
18381            return directives;
18382          }]);
18383      }
18384      hasDirectives[name].push(directiveFactory);
18385    } else {
18386      forEach(name, reverseParams(registerDirective));
18387    }
18388    return this;
18389  };
18390
18391  /**
18392   * @ngdoc method
18393   * @name $compileProvider#component
18394   * @module ng
18395   * @param {string} name Name of the component in camelCase (i.e. `myComp` which will match `<my-comp>`)
18396   * @param {Object} options Component definition object (a simplified
18397   *    {@link ng.$compile#directive-definition-object directive definition object}),
18398   *    with the following properties (all optional):
18399   *
18400   *    - `controller` – `{(string|function()=}` – controller constructor function that should be
18401   *      associated with newly created scope or the name of a {@link ng.$compile#-controller-
18402   *      registered controller} if passed as a string. An empty `noop` function by default.
18403   *    - `controllerAs` – `{string=}` – identifier name for to reference the controller in the component's scope.
18404   *      If present, the controller will be published to scope under the `controllerAs` name.
18405   *      If not present, this will default to be `$ctrl`.
18406   *    - `template` – `{string=|function()=}` – html template as a string or a function that
18407   *      returns an html template as a string which should be used as the contents of this component.
18408   *      Empty string by default.
18409   *
18410   *      If `template` is a function, then it is {@link auto.$injector#invoke injected} with
18411   *      the following locals:
18412   *
18413   *      - `$element` - Current element
18414   *      - `$attrs` - Current attributes object for the element
18415   *
18416   *    - `templateUrl` – `{string=|function()=}` – path or function that returns a path to an html
18417   *      template that should be used  as the contents of this component.
18418   *
18419   *      If `templateUrl` is a function, then it is {@link auto.$injector#invoke injected} with
18420   *      the following locals:
18421   *
18422   *      - `$element` - Current element
18423   *      - `$attrs` - Current attributes object for the element
18424   *
18425   *    - `bindings` – `{object=}` – defines bindings between DOM attributes and component properties.
18426   *      Component properties are always bound to the component controller and not to the scope.
18427   *      See {@link ng.$compile#-bindtocontroller- `bindToController`}.
18428   *    - `transclude` – `{boolean=}` – whether {@link $compile#transclusion content transclusion} is enabled.
18429   *      Disabled by default.
18430   *    - `require` - `{Object<string, string>=}` - requires the controllers of other directives and binds them to
18431   *      this component's controller. The object keys specify the property names under which the required
18432   *      controllers (object values) will be bound. See {@link ng.$compile#-require- `require`}.
18433   *    - `$...` – additional properties to attach to the directive factory function and the controller
18434   *      constructor function. (This is used by the component router to annotate)
18435   *
18436   * @returns {ng.$compileProvider} the compile provider itself, for chaining of function calls.
18437   * @description
18438   * Register a **component definition** with the compiler. This is a shorthand for registering a special
18439   * type of directive, which represents a self-contained UI component in your application. Such components
18440   * are always isolated (i.e. `scope: {}`) and are always restricted to elements (i.e. `restrict: 'E'`).
18441   *
18442   * Component definitions are very simple and do not require as much configuration as defining general
18443   * directives. Component definitions usually consist only of a template and a controller backing it.
18444   *
18445   * In order to make the definition easier, components enforce best practices like use of `controllerAs`,
18446   * `bindToController`. They always have **isolate scope** and are restricted to elements.
18447   *
18448   * Here are a few examples of how you would usually define components:
18449   *
18450   * ```js
18451   *   var myMod = angular.module(...);
18452   *   myMod.component('myComp', {
18453   *     template: '<div>My name is {{$ctrl.name}}</div>',
18454   *     controller: function() {
18455   *       this.name = 'shahar';
18456   *     }
18457   *   });
18458   *
18459   *   myMod.component('myComp', {
18460   *     template: '<div>My name is {{$ctrl.name}}</div>',
18461   *     bindings: {name: '@'}
18462   *   });
18463   *
18464   *   myMod.component('myComp', {
18465   *     templateUrl: 'views/my-comp.html',
18466   *     controller: 'MyCtrl',
18467   *     controllerAs: 'ctrl',
18468   *     bindings: {name: '@'}
18469   *   });
18470   *
18471   * ```
18472   * For more examples, and an in-depth guide, see the {@link guide/component component guide}.
18473   *
18474   * <br />
18475   * See also {@link ng.$compileProvider#directive $compileProvider.directive()}.
18476   */
18477  this.component = function registerComponent(name, options) {
18478    var controller = options.controller || function() {};
18479
18480    function factory($injector) {
18481      function makeInjectable(fn) {
18482        if (isFunction(fn) || isArray(fn)) {
18483          return /** @this */ function(tElement, tAttrs) {
18484            return $injector.invoke(fn, this, {$element: tElement, $attrs: tAttrs});
18485          };
18486        } else {
18487          return fn;
18488        }
18489      }
18490
18491      var template = (!options.template && !options.templateUrl ? '' : options.template);
18492      var ddo = {
18493        controller: controller,
18494        controllerAs: identifierForController(options.controller) || options.controllerAs || '$ctrl',
18495        template: makeInjectable(template),
18496        templateUrl: makeInjectable(options.templateUrl),
18497        transclude: options.transclude,
18498        scope: {},
18499        bindToController: options.bindings || {},
18500        restrict: 'E',
18501        require: options.require
18502      };
18503
18504      // Copy annotations (starting with $) over to the DDO
18505      forEach(options, function(val, key) {
18506        if (key.charAt(0) === '$') ddo[key] = val;
18507      });
18508
18509      return ddo;
18510    }
18511
18512    // TODO(pete) remove the following `forEach` before we release 1.6.0
18513    // The [email protected] looks for the annotations on the controller constructor
18514    // Nothing in Angular looks for annotations on the factory function but we can't remove
18515    // it from 1.5.x yet.
18516
18517    // Copy any annotation properties (starting with $) over to the factory and controller constructor functions
18518    // These could be used by libraries such as the new component router
18519    forEach(options, function(val, key) {
18520      if (key.charAt(0) === '$') {
18521        factory[key] = val;
18522        // Don't try to copy over annotations to named controller
18523        if (isFunction(controller)) controller[key] = val;
18524      }
18525    });
18526
18527    factory.$inject = ['$injector'];
18528
18529    return this.directive(name, factory);
18530  };
18531
18532
18533  /**
18534   * @ngdoc method
18535   * @name $compileProvider#aHrefSanitizationWhitelist
18536   * @kind function
18537   *
18538   * @description
18539   * Retrieves or overrides the default regular expression that is used for whitelisting of safe
18540   * urls during a[href] sanitization.
18541   *
18542   * The sanitization is a security measure aimed at preventing XSS attacks via html links.
18543   *
18544   * Any url about to be assigned to a[href] via data-binding is first normalized and turned into
18545   * an absolute url. Afterwards, the url is matched against the `aHrefSanitizationWhitelist`
18546   * regular expression. If a match is found, the original url is written into the dom. Otherwise,
18547   * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM.
18548   *
18549   * @param {RegExp=} regexp New regexp to whitelist urls with.
18550   * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
18551   *    chaining otherwise.
18552   */
18553  this.aHrefSanitizationWhitelist = function(regexp) {
18554    if (isDefined(regexp)) {
18555      $$sanitizeUriProvider.aHrefSanitizationWhitelist(regexp);
18556      return this;
18557    } else {
18558      return $$sanitizeUriProvider.aHrefSanitizationWhitelist();
18559    }
18560  };
18561
18562
18563  /**
18564   * @ngdoc method
18565   * @name $compileProvider#imgSrcSanitizationWhitelist
18566   * @kind function
18567   *
18568   * @description
18569   * Retrieves or overrides the default regular expression that is used for whitelisting of safe
18570   * urls during img[src] sanitization.
18571   *
18572   * The sanitization is a security measure aimed at prevent XSS attacks via html links.
18573   *
18574   * Any url about to be assigned to img[src] via data-binding is first normalized and turned into
18575   * an absolute url. Afterwards, the url is matched against the `imgSrcSanitizationWhitelist`
18576   * regular expression. If a match is found, the original url is written into the dom. Otherwise,
18577   * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM.
18578   *
18579   * @param {RegExp=} regexp New regexp to whitelist urls with.
18580   * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
18581   *    chaining otherwise.
18582   */
18583  this.imgSrcSanitizationWhitelist = function(regexp) {
18584    if (isDefined(regexp)) {
18585      $$sanitizeUriProvider.imgSrcSanitizationWhitelist(regexp);
18586      return this;
18587    } else {
18588      return $$sanitizeUriProvider.imgSrcSanitizationWhitelist();
18589    }
18590  };
18591
18592  /**
18593   * @ngdoc method
18594   * @name  $compileProvider#debugInfoEnabled
18595   *
18596   * @param {boolean=} enabled update the debugInfoEnabled state if provided, otherwise just return the
18597   * current debugInfoEnabled state
18598   * @returns {*} current value if used as getter or itself (chaining) if used as setter
18599   *
18600   * @kind function
18601   *
18602   * @description
18603   * Call this method to enable/disable various debug runtime information in the compiler such as adding
18604   * binding information and a reference to the current scope on to DOM elements.
18605   * If enabled, the compiler will add the following to DOM elements that have been bound to the scope
18606   * * `ng-binding` CSS class
18607   * * `$binding` data property containing an array of the binding expressions
18608   *
18609   * You may want to disable this in production for a significant performance boost. See
18610   * {@link guide/production#disabling-debug-data Disabling Debug Data} for more.
18611   *
18612   * The default value is true.
18613   */
18614  var debugInfoEnabled = true;
18615  this.debugInfoEnabled = function(enabled) {
18616    if (isDefined(enabled)) {
18617      debugInfoEnabled = enabled;
18618      return this;
18619    }
18620    return debugInfoEnabled;
18621  };
18622
18623  /**
18624   * @ngdoc method
18625   * @name  $compileProvider#preAssignBindingsEnabled
18626   *
18627   * @param {boolean=} enabled update the preAssignBindingsEnabled state if provided, otherwise just return the
18628   * current preAssignBindingsEnabled state
18629   * @returns {*} current value if used as getter or itself (chaining) if used as setter
18630   *
18631   * @kind function
18632   *
18633   * @description
18634   * Call this method to enable/disable whether directive controllers are assigned bindings before
18635   * calling the controller's constructor.
18636   * If enabled (true), the compiler assigns the value of each of the bindings to the
18637   * properties of the controller object before the constructor of this object is called.
18638   *
18639   * If disabled (false), the compiler calls the constructor first before assigning bindings.
18640   *
18641   * The default value is true in Angular 1.5.x but will switch to false in Angular 1.6.x.
18642   */
18643  var preAssignBindingsEnabled = false;
18644  this.preAssignBindingsEnabled = function(enabled) {
18645    if (isDefined(enabled)) {
18646      preAssignBindingsEnabled = enabled;
18647      return this;
18648    }
18649    return preAssignBindingsEnabled;
18650  };
18651
18652
18653  var TTL = 10;
18654  /**
18655   * @ngdoc method
18656   * @name $compileProvider#onChangesTtl
18657   * @description
18658   *
18659   * Sets the number of times `$onChanges` hooks can trigger new changes before giving up and
18660   * assuming that the model is unstable.
18661   *
18662   * The current default is 10 iterations.
18663   *
18664   * In complex applications it's possible that dependencies between `$onChanges` hooks and bindings will result
18665   * in several iterations of calls to these hooks. However if an application needs more than the default 10
18666   * iterations to stabilize then you should investigate what is causing the model to continuously change during
18667   * the `$onChanges` hook execution.
18668   *
18669   * Increasing the TTL could have performance implications, so you should not change it without proper justification.
18670   *
18671   * @param {number} limit The number of `$onChanges` hook iterations.
18672   * @returns {number|object} the current limit (or `this` if called as a setter for chaining)
18673   */
18674  this.onChangesTtl = function(value) {
18675    if (arguments.length) {
18676      TTL = value;
18677      return this;
18678    }
18679    return TTL;
18680  };
18681
18682  var commentDirectivesEnabledConfig = true;
18683  /**
18684   * @ngdoc method
18685   * @name $compileProvider#commentDirectivesEnabled
18686   * @description
18687   *
18688   * It indicates to the compiler
18689   * whether or not directives on comments should be compiled.
18690   * Defaults to `true`.
18691   *
18692   * Calling this function with false disables the compilation of directives
18693   * on comments for the whole application.
18694   * This results in a compilation performance gain,
18695   * as the compiler doesn't have to check comments when looking for directives.
18696   * This should however only be used if you are sure that no comment directives are used in
18697   * the application (including any 3rd party directives).
18698   *
18699   * @param {boolean} enabled `false` if the compiler may ignore directives on comments
18700   * @returns {boolean|object} the current value (or `this` if called as a setter for chaining)
18701   */
18702  this.commentDirectivesEnabled = function(value) {
18703    if (arguments.length) {
18704      commentDirectivesEnabledConfig = value;
18705      return this;
18706    }
18707    return commentDirectivesEnabledConfig;
18708  };
18709
18710
18711  var cssClassDirectivesEnabledConfig = true;
18712  /**
18713   * @ngdoc method
18714   * @name $compileProvider#cssClassDirectivesEnabled
18715   * @description
18716   *
18717   * It indicates to the compiler
18718   * whether or not directives on element classes should be compiled.
18719   * Defaults to `true`.
18720   *
18721   * Calling this function with false disables the compilation of directives
18722   * on element classes for the whole application.
18723   * This results in a compilation performance gain,
18724   * as the compiler doesn't have to check element classes when looking for directives.
18725   * This should however only be used if you are sure that no class directives are used in
18726   * the application (including any 3rd party directives).
18727   *
18728   * @param {boolean} enabled `false` if the compiler may ignore directives on element classes
18729   * @returns {boolean|object} the current value (or `this` if called as a setter for chaining)
18730   */
18731  this.cssClassDirectivesEnabled = function(value) {
18732    if (arguments.length) {
18733      cssClassDirectivesEnabledConfig = value;
18734      return this;
18735    }
18736    return cssClassDirectivesEnabledConfig;
18737  };
18738
18739  this.$get = [
18740            '$injector', '$interpolate', '$exceptionHandler', '$templateRequest', '$parse',
18741            '$controller', '$rootScope', '$sce', '$animate', '$$sanitizeUri',
18742    function($injector,   $interpolate,   $exceptionHandler,   $templateRequest,   $parse,
18743             $controller,   $rootScope,   $sce,   $animate,   $$sanitizeUri) {
18744
18745    var SIMPLE_ATTR_NAME = /^\w/;
18746    var specialAttrHolder = window.document.createElement('div');
18747
18748
18749    var commentDirectivesEnabled = commentDirectivesEnabledConfig;
18750    var cssClassDirectivesEnabled = cssClassDirectivesEnabledConfig;
18751
18752
18753    var onChangesTtl = TTL;
18754    // The onChanges hooks should all be run together in a single digest
18755    // When changes occur, the call to trigger their hooks will be added to this queue
18756    var onChangesQueue;
18757
18758    // This function is called in a $$postDigest to trigger all the onChanges hooks in a single digest
18759    function flushOnChangesQueue() {
18760      try {
18761        if (!(--onChangesTtl)) {
18762          // We have hit the TTL limit so reset everything
18763          onChangesQueue = undefined;
18764          throw $compileMinErr('infchng', '{0} $onChanges() iterations reached. Aborting!\n', TTL);
18765        }
18766        // We must run this hook in an apply since the $$postDigest runs outside apply
18767        $rootScope.$apply(function() {
18768          var errors = [];
18769          for (var i = 0, ii = onChangesQueue.length; i < ii; ++i) {
18770            try {
18771              onChangesQueue[i]();
18772            } catch (e) {
18773              errors.push(e);
18774            }
18775          }
18776          // Reset the queue to trigger a new schedule next time there is a change
18777          onChangesQueue = undefined;
18778          if (errors.length) {
18779            throw errors;
18780          }
18781        });
18782      } finally {
18783        onChangesTtl++;
18784      }
18785    }
18786
18787
18788    function Attributes(element, attributesToCopy) {
18789      if (attributesToCopy) {
18790        var keys = Object.keys(attributesToCopy);
18791        var i, l, key;
18792
18793        for (i = 0, l = keys.length; i < l; i++) {
18794          key = keys[i];
18795          this[key] = attributesToCopy[key];
18796        }
18797      } else {
18798        this.$attr = {};
18799      }
18800
18801      this.$$element = element;
18802    }
18803
18804    Attributes.prototype = {
18805      /**
18806       * @ngdoc method
18807       * @name $compile.directive.Attributes#$normalize
18808       * @kind function
18809       *
18810       * @description
18811       * Converts an attribute name (e.g. dash/colon/underscore-delimited string, optionally prefixed with `x-` or
18812       * `data-`) to its normalized, camelCase form.
18813       *
18814       * Also there is special case for Moz prefix starting with upper case letter.
18815       *
18816       * For further information check out the guide on {@link guide/directive#matching-directives Matching Directives}
18817       *
18818       * @param {string} name Name to normalize
18819       */
18820      $normalize: directiveNormalize,
18821
18822
18823      /**
18824       * @ngdoc method
18825       * @name $compile.directive.Attributes#$addClass
18826       * @kind function
18827       *
18828       * @description
18829       * Adds the CSS class value specified by the classVal parameter to the element. If animations
18830       * are enabled then an animation will be triggered for the class addition.
18831       *
18832       * @param {string} classVal The className value that will be added to the element
18833       */
18834      $addClass: function(classVal) {
18835        if (classVal && classVal.length > 0) {
18836          $animate.addClass(this.$$element, classVal);
18837        }
18838      },
18839
18840      /**
18841       * @ngdoc method
18842       * @name $compile.directive.Attributes#$removeClass
18843       * @kind function
18844       *
18845       * @description
18846       * Removes the CSS class value specified by the classVal parameter from the element. If
18847       * animations are enabled then an animation will be triggered for the class removal.
18848       *
18849       * @param {string} classVal The className value that will be removed from the element
18850       */
18851      $removeClass: function(classVal) {
18852        if (classVal && classVal.length > 0) {
18853          $animate.removeClass(this.$$element, classVal);
18854        }
18855      },
18856
18857      /**
18858       * @ngdoc method
18859       * @name $compile.directive.Attributes#$updateClass
18860       * @kind function
18861       *
18862       * @description
18863       * Adds and removes the appropriate CSS class values to the element based on the difference
18864       * between the new and old CSS class values (specified as newClasses and oldClasses).
18865       *
18866       * @param {string} newClasses The current CSS className value
18867       * @param {string} oldClasses The former CSS className value
18868       */
18869      $updateClass: function(newClasses, oldClasses) {
18870        var toAdd = tokenDifference(newClasses, oldClasses);
18871        if (toAdd && toAdd.length) {
18872          $animate.addClass(this.$$element, toAdd);
18873        }
18874
18875        var toRemove = tokenDifference(oldClasses, newClasses);
18876        if (toRemove && toRemove.length) {
18877          $animate.removeClass(this.$$element, toRemove);
18878        }
18879      },
18880
18881      /**
18882       * Set a normalized attribute on the element in a way such that all directives
18883       * can share the attribute. This function properly handles boolean attributes.
18884       * @param {string} key Normalized key. (ie ngAttribute)
18885       * @param {string|boolean} value The value to set. If `null` attribute will be deleted.
18886       * @param {boolean=} writeAttr If false, does not write the value to DOM element attribute.
18887       *     Defaults to true.
18888       * @param {string=} attrName Optional none normalized name. Defaults to key.
18889       */
18890      $set: function(key, value, writeAttr, attrName) {
18891        // TODO: decide whether or not to throw an error if "class"
18892        //is set through this function since it may cause $updateClass to
18893        //become unstable.
18894
18895        var node = this.$$element[0],
18896            booleanKey = getBooleanAttrName(node, key),
18897            aliasedKey = getAliasedAttrName(key),
18898            observer = key,
18899            nodeName;
18900
18901        if (booleanKey) {
18902          this.$$element.prop(key, value);
18903          attrName = booleanKey;
18904        } else if (aliasedKey) {
18905          this[aliasedKey] = value;
18906          observer = aliasedKey;
18907        }
18908
18909        this[key] = value;
18910
18911        // translate normalized key to actual key
18912        if (attrName) {
18913          this.$attr[key] = attrName;
18914        } else {
18915          attrName = this.$attr[key];
18916          if (!attrName) {
18917            this.$attr[key] = attrName = snake_case(key, '-');
18918          }
18919        }
18920
18921        nodeName = nodeName_(this.$$element);
18922
18923        if ((nodeName === 'a' && (key === 'href' || key === 'xlinkHref')) ||
18924            (nodeName === 'img' && key === 'src')) {
18925          // sanitize a[href] and img[src] values
18926          this[key] = value = $$sanitizeUri(value, key === 'src');
18927        } else if (nodeName === 'img' && key === 'srcset' && isDefined(value)) {
18928          // sanitize img[srcset] values
18929          var result = '';
18930
18931          // first check if there are spaces because it's not the same pattern
18932          var trimmedSrcset = trim(value);
18933          //                (   999x   ,|   999w   ,|   ,|,   )
18934          var srcPattern = /(\s+\d+x\s*,|\s+\d+w\s*,|\s+,|,\s+)/;
18935          var pattern = /\s/.test(trimmedSrcset) ? srcPattern : /(,)/;
18936
18937          // split srcset into tuple of uri and descriptor except for the last item
18938          var rawUris = trimmedSrcset.split(pattern);
18939
18940          // for each tuples
18941          var nbrUrisWith2parts = Math.floor(rawUris.length / 2);
18942          for (var i = 0; i < nbrUrisWith2parts; i++) {
18943            var innerIdx = i * 2;
18944            // sanitize the uri
18945            result += $$sanitizeUri(trim(rawUris[innerIdx]), true);
18946            // add the descriptor
18947            result += (' ' + trim(rawUris[innerIdx + 1]));
18948          }
18949
18950          // split the last item into uri and descriptor
18951          var lastTuple = trim(rawUris[i * 2]).split(/\s/);
18952
18953          // sanitize the last uri
18954          result += $$sanitizeUri(trim(lastTuple[0]), true);
18955
18956          // and add the last descriptor if any
18957          if (lastTuple.length === 2) {
18958            result += (' ' + trim(lastTuple[1]));
18959          }
18960          this[key] = value = result;
18961        }
18962
18963        if (writeAttr !== false) {
18964          if (value === null || isUndefined(value)) {
18965            this.$$element.removeAttr(attrName);
18966          } else {
18967            if (SIMPLE_ATTR_NAME.test(attrName)) {
18968              this.$$element.attr(attrName, value);
18969            } else {
18970              setSpecialAttr(this.$$element[0], attrName, value);
18971            }
18972          }
18973        }
18974
18975        // fire observers
18976        var $$observers = this.$$observers;
18977        if ($$observers) {
vendor: 6,838 bytes, lines 18978-19148
18978          forEach($$observers[observer], function(fn) {
18979            try {
18980              fn(value);
18981            } catch (e) {
18982              $exceptionHandler(e);
18983            }
18984          });
18985        }
18986      },
18987
18988
18989      /**
18990       * @ngdoc method
18991       * @name $compile.directive.Attributes#$observe
18992       * @kind function
18993       *
18994       * @description
18995       * Observes an interpolated attribute.
18996       *
18997       * The observer function will be invoked once during the next `$digest` following
18998       * compilation. The observer is then invoked whenever the interpolated value
18999       * changes.
19000       *
19001       * @param {string} key Normalized key. (ie ngAttribute) .
19002       * @param {function(interpolatedValue)} fn Function that will be called whenever
19003                the interpolated value of the attribute changes.
19004       *        See the {@link guide/interpolation#how-text-and-attribute-bindings-work Interpolation
19005       *        guide} for more info.
19006       * @returns {function()} Returns a deregistration function for this observer.
19007       */
19008      $observe: function(key, fn) {
19009        var attrs = this,
19010            $$observers = (attrs.$$observers || (attrs.$$observers = createMap())),
19011            listeners = ($$observers[key] || ($$observers[key] = []));
19012
19013        listeners.push(fn);
19014        $rootScope.$evalAsync(function() {
19015          if (!listeners.$$inter && attrs.hasOwnProperty(key) && !isUndefined(attrs[key])) {
19016            // no one registered attribute interpolation function, so lets call it manually
19017            fn(attrs[key]);
19018          }
19019        });
19020
19021        return function() {
19022          arrayRemove(listeners, fn);
19023        };
19024      }
19025    };
19026
19027    function setSpecialAttr(element, attrName, value) {
19028      // Attributes names that do not start with letters (such as `(click)`) cannot be set using `setAttribute`
19029      // so we have to jump through some hoops to get such an attribute
19030      // https://github.com/angular/angular.js/pull/13318
19031      specialAttrHolder.innerHTML = '<span ' + attrName + '>';
19032      var attributes = specialAttrHolder.firstChild.attributes;
19033      var attribute = attributes[0];
19034      // We have to remove the attribute from its container element before we can add it to the destination element
19035      attributes.removeNamedItem(attribute.name);
19036      attribute.value = value;
19037      element.attributes.setNamedItem(attribute);
19038    }
19039
19040    function safeAddClass($element, className) {
19041      try {
19042        $element.addClass(className);
19043      } catch (e) {
19044        // ignore, since it means that we are trying to set class on
19045        // SVG element, where class name is read-only.
19046      }
19047    }
19048
19049
19050    var startSymbol = $interpolate.startSymbol(),
19051        endSymbol = $interpolate.endSymbol(),
19052        denormalizeTemplate = (startSymbol === '{{' && endSymbol  === '}}')
19053            ? identity
19054            : function denormalizeTemplate(template) {
19055              return template.replace(/\{\{/g, startSymbol).replace(/}}/g, endSymbol);
19056        },
19057        NG_ATTR_BINDING = /^ngAttr[A-Z]/;
19058    var MULTI_ELEMENT_DIR_RE = /^(.+)Start$/;
19059
19060    compile.$$addBindingInfo = debugInfoEnabled ? function $$addBindingInfo($element, binding) {
19061      var bindings = $element.data('$binding') || [];
19062
19063      if (isArray(binding)) {
19064        bindings = bindings.concat(binding);
19065      } else {
19066        bindings.push(binding);
19067      }
19068
19069      $element.data('$binding', bindings);
19070    } : noop;
19071
19072    compile.$$addBindingClass = debugInfoEnabled ? function $$addBindingClass($element) {
19073      safeAddClass($element, 'ng-binding');
19074    } : noop;
19075
19076    compile.$$addScopeInfo = debugInfoEnabled ? function $$addScopeInfo($element, scope, isolated, noTemplate) {
19077      var dataName = isolated ? (noTemplate ? '$isolateScopeNoTemplate' : '$isolateScope') : '$scope';
19078      $element.data(dataName, scope);
19079    } : noop;
19080
19081    compile.$$addScopeClass = debugInfoEnabled ? function $$addScopeClass($element, isolated) {
19082      safeAddClass($element, isolated ? 'ng-isolate-scope' : 'ng-scope');
19083    } : noop;
19084
19085    compile.$$createComment = function(directiveName, comment) {
19086      var content = '';
19087      if (debugInfoEnabled) {
19088        content = ' ' + (directiveName || '') + ': ';
19089        if (comment) content += comment + ' ';
19090      }
19091      return window.document.createComment(content);
19092    };
19093
19094    return compile;
19095
19096    //================================
19097
19098    function compile($compileNodes, transcludeFn, maxPriority, ignoreDirective,
19099                        previousCompileContext) {
19100      if (!($compileNodes instanceof jqLite)) {
19101        // jquery always rewraps, whereas we need to preserve the original selector so that we can
19102        // modify it.
19103        $compileNodes = jqLite($compileNodes);
19104      }
19105      var compositeLinkFn =
19106              compileNodes($compileNodes, transcludeFn, $compileNodes,
19107                           maxPriority, ignoreDirective, previousCompileContext);
19108      compile.$$addScopeClass($compileNodes);
19109      var namespace = null;
19110      return function publicLinkFn(scope, cloneConnectFn, options) {
19111        if (!$compileNodes) {
19112          throw $compileMinErr('multilink', 'This element has already been linked.');
19113        }
19114        assertArg(scope, 'scope');
19115
19116        if (previousCompileContext && previousCompileContext.needsNewScope) {
19117          // A parent directive did a replace and a directive on this element asked
19118          // for transclusion, which caused us to lose a layer of element on which
19119          // we could hold the new transclusion scope, so we will create it manually
19120          // here.
19121          scope = scope.$parent.$new();
19122        }
19123
19124        options = options || {};
19125        var parentBoundTranscludeFn = options.parentBoundTranscludeFn,
19126          transcludeControllers = options.transcludeControllers,
19127          futureParentElement = options.futureParentElement;
19128
19129        // When `parentBoundTranscludeFn` is passed, it is a
19130        // `controllersBoundTransclude` function (it was previously passed
19131        // as `transclude` to directive.link) so we must unwrap it to get
19132        // its `boundTranscludeFn`
19133        if (parentBoundTranscludeFn && parentBoundTranscludeFn.$$boundTransclude) {
19134          parentBoundTranscludeFn = parentBoundTranscludeFn.$$boundTransclude;
19135        }
19136
19137        if (!namespace) {
19138          namespace = detectNamespaceForChildElements(futureParentElement);
19139        }
19140        var $linkNode;
19141        if (namespace !== 'html') {
19142          // When using a directive with replace:true and templateUrl the $compileNodes
19143          // (or a child element inside of them)
19144          // might change, so we need to recreate the namespace adapted compileNodes
19145          // for call to the link function.
19146          // Note: This will already clone the nodes...
19147          $linkNode = jqLite(
19148            wrapTemplate(namespace, jqLite('<
vendor: 9,507 bytes, lines 19148-19393
19148div>').append($compileNodes).html())
19149          );
19150        } else if (cloneConnectFn) {
19151          // important!!: we must call our jqLite.clone() since the jQuery one is trying to be smart
19152          // and sometimes changes the structure of the DOM.
19153          $linkNode = JQLitePrototype.clone.call($compileNodes);
19154        } else {
19155          $linkNode = $compileNodes;
19156        }
19157
19158        if (transcludeControllers) {
19159          for (var controllerName in transcludeControllers) {
19160            $linkNode.data('$' + controllerName + 'Controller', transcludeControllers[controllerName].instance);
19161          }
19162        }
19163
19164        compile.$$addScopeInfo($linkNode, scope);
19165
19166        if (cloneConnectFn) cloneConnectFn($linkNode, scope);
19167        if (compositeLinkFn) compositeLinkFn(scope, $linkNode, $linkNode, parentBoundTranscludeFn);
19168
19169        if (!cloneConnectFn) {
19170          $compileNodes = compositeLinkFn = null;
19171        }
19172        return $linkNode;
19173      };
19174    }
19175
19176    function detectNamespaceForChildElements(parentElement) {
19177      // TODO: Make this detect MathML as well...
19178      var node = parentElement && parentElement[0];
19179      if (!node) {
19180        return 'html';
19181      } else {
19182        return nodeName_(node) !== 'foreignobject' && toString.call(node).match(/SVG/) ? 'svg' : 'html';
19183      }
19184    }
19185
19186    /**
19187     * Compile function matches each node in nodeList against the directives. Once all directives
19188     * for a particular node are collected their compile functions are executed. The compile
19189     * functions return values - the linking functions - are combined into a composite linking
19190     * function, which is the a linking function for the node.
19191     *
19192     * @param {NodeList} nodeList an array of nodes or NodeList to compile
19193     * @param {function(angular.Scope, cloneAttachFn=)} transcludeFn A linking function, where the
19194     *        scope argument is auto-generated to the new child of the transcluded parent scope.
19195     * @param {DOMElement=} $rootElement If the nodeList is the root of the compilation tree then
19196     *        the rootElement must be set the jqLite collection of the compile root. This is
19197     *        needed so that the jqLite collection items can be replaced with widgets.
19198     * @param {number=} maxPriority Max directive priority.
19199     * @returns {Function} A composite linking function of all of the matched directives or null.
19200     */
19201    function compileNodes(nodeList, transcludeFn, $rootElement, maxPriority, ignoreDirective,
19202                            previousCompileContext) {
19203      var linkFns = [],
19204          // `nodeList` can be either an element's `.childNodes` (live NodeList)
19205          // or a jqLite/jQuery collection or an array
19206          notLiveList = isArray(nodeList) || (nodeList instanceof jqLite),
19207          attrs, directives, nodeLinkFn, childNodes, childLinkFn, linkFnFound, nodeLinkFnFound;
19208
19209
19210      for (var i = 0; i < nodeList.length; i++) {
19211        attrs = new Attributes();
19212
19213        // Support: IE 11 only
19214        // Workaround for #11781 and #14924
19215        if (msie === 11) {
19216          mergeConsecutiveTextNodes(nodeList, i, notLiveList);
19217        }
19218
19219        // We must always refer to `nodeList[i]` hereafter,
19220        // since the nodes can be replaced underneath us.
19221        directives = collectDirectives(nodeList[i], [], attrs, i === 0 ? maxPriority : undefined,
19222                                        ignoreDirective);
19223
19224        nodeLinkFn = (directives.length)
19225            ? applyDirectivesToNode(directives, nodeList[i], attrs, transcludeFn, $rootElement,
19226                                      null, [], [], previousCompileContext)
19227            : null;
19228
19229        if (nodeLinkFn && nodeLinkFn.scope) {
19230          compile.$$addScopeClass(attrs.$$element);
19231        }
19232
19233        childLinkFn = (nodeLinkFn && nodeLinkFn.terminal ||
19234                      !(childNodes = nodeList[i].childNodes) ||
19235                      !childNodes.length)
19236            ? null
19237            : compileNodes(childNodes,
19238                 nodeLinkFn ? (
19239                  (nodeLinkFn.transcludeOnThisElement || !nodeLinkFn.templateOnThisElement)
19240                     && nodeLinkFn.transclude) : transcludeFn);
19241
19242        if (nodeLinkFn || childLinkFn) {
19243          linkFns.push(i, nodeLinkFn, childLinkFn);
19244          linkFnFound = true;
19245          nodeLinkFnFound = nodeLinkFnFound || nodeLinkFn;
19246        }
19247
19248        //use the previous context only for the first element in the virtual group
19249        previousCompileContext = null;
19250      }
19251
19252      // return a linking function if we have found anything, null otherwise
19253      return linkFnFound ? compositeLinkFn : null;
19254
19255      function compositeLinkFn(scope, nodeList, $rootElement, parentBoundTranscludeFn) {
19256        var nodeLinkFn, childLinkFn, node, childScope, i, ii, idx, childBoundTranscludeFn;
19257        var stableNodeList;
19258
19259
19260        if (nodeLinkFnFound) {
19261          // copy nodeList so that if a nodeLinkFn removes or adds an element at this DOM level our
19262          // offsets don't get screwed up
19263          var nodeListLength = nodeList.length;
19264          stableNodeList = new Array(nodeListLength);
19265
19266          // create a sparse array by only copying the elements which have a linkFn
19267          for (i = 0; i < linkFns.length; i += 3) {
19268            idx = linkFns[i];
19269            stableNodeList[idx] = nodeList[idx];
19270          }
19271        } else {
19272          stableNodeList = nodeList;
19273        }
19274
19275        for (i = 0, ii = linkFns.length; i < ii;) {
19276          node = stableNodeList[linkFns[i++]];
19277          nodeLinkFn = linkFns[i++];
19278          childLinkFn = linkFns[i++];
19279
19280          if (nodeLinkFn) {
19281            if (nodeLinkFn.scope) {
19282              childScope = scope.$new();
19283              compile.$$addScopeInfo(jqLite(node), childScope);
19284            } else {
19285              childScope = scope;
19286            }
19287
19288            if (nodeLinkFn.transcludeOnThisElement) {
19289              childBoundTranscludeFn = createBoundTranscludeFn(
19290                  scope, nodeLinkFn.transclude, parentBoundTranscludeFn);
19291
19292            } else if (!nodeLinkFn.templateOnThisElement && parentBoundTranscludeFn) {
19293              childBoundTranscludeFn = parentBoundTranscludeFn;
19294
19295            } else if (!parentBoundTranscludeFn && transcludeFn) {
19296              childBoundTranscludeFn = createBoundTranscludeFn(scope, transcludeFn);
19297
19298            } else {
19299              childBoundTranscludeFn = null;
19300            }
19301
19302            nodeLinkFn(childLinkFn, childScope, node, $rootElement, childBoundTranscludeFn);
19303
19304          } else if (childLinkFn) {
19305            childLinkFn(scope, node.childNodes, undefined, parentBoundTranscludeFn);
19306          }
19307        }
19308      }
19309    }
19310
19311    function mergeConsecutiveTextNodes(nodeList, idx, notLiveList) {
19312      var node = nodeList[idx];
19313      var parent = node.parentNode;
19314      var sibling;
19315
19316      if (node.nodeType !== NODE_TYPE_TEXT) {
19317        return;
19318      }
19319
19320      while (true) {
19321        sibling = parent ? node.nextSibling : nodeList[idx + 1];
19322        if (!sibling || sibling.nodeType !== NODE_TYPE_TEXT) {
19323          break;
19324        }
19325
19326        node.nodeValue = node.nodeValue + sibling.nodeValue;
19327
19328        if (sibling.parentNode) {
19329          sibling.parentNode.removeChild(sibling);
19330        }
19331        if (notLiveList && sibling === nodeList[idx + 1]) {
19332          nodeList.splice(idx + 1, 1);
19333        }
19334      }
19335    }
19336
19337    function createBoundTranscludeFn(scope, transcludeFn, previousBoundTranscludeFn) {
19338      function boundTranscludeFn(transcludedScope, cloneFn, controllers, futureParentElement, containingScope) {
19339
19340        if (!transcludedScope) {
19341          transcludedScope = scope.$new(false, containingScope);
19342          transcludedScope.$$transcluded = true;
19343        }
19344
19345        return transcludeFn(transcludedScope, cloneFn, {
19346          parentBoundTranscludeFn: previousBoundTranscludeFn,
19347          transcludeControllers: controllers,
19348          futureParentElement: futureParentElement
19349        });
19350      }
19351
19352      // We need  to attach the transclusion slots onto the `boundTranscludeFn`
19353      // so that they are available inside the `controllersBoundTransclude` function
19354      var boundSlots = boundTranscludeFn.$$slots = createMap();
19355      for (var slotName in transcludeFn.$$slots) {
19356        if (transcludeFn.$$slots[slotName]) {
19357          boundSlots[slotName] = createBoundTranscludeFn(scope, transcludeFn.$$slots[slotName], previousBoundTranscludeFn);
19358        } else {
19359          boundSlots[slotName] = null;
19360        }
19361      }
19362
19363      return boundTranscludeFn;
19364    }
19365
19366    /**
19367     * Looks for directives on the given node and adds them to the directive collection which is
19368     * sorted.
19369     *
19370     * @param node Node to search.
19371     * @param directives An array to which the directives are added to. This array is sorted before
19372     *        the function returns.
19373     * @param attrs The shared attrs object which is used to populate the normalized attributes.
19374     * @param {number=} maxPriority Max directive priority.
19375     */
19376    function collectDirectives(node, directives, attrs, maxPriority, ignoreDirective) {
19377      var nodeType = node.nodeType,
19378          attrsMap = attrs.$attr,
19379          match,
19380          nodeName,
19381          className;
19382
19383      switch (nodeType) {
19384        case NODE_TYPE_ELEMENT: /* Element */
19385
19386          nodeName = nodeName_(node);
19387
19388          // use the node name: <directive>
19389          addDirective(directives,
19390              directiveNormalize(nodeName), 'E', maxPriority, ignoreDirective);
19391
19392          // iterate over the attributes
19393          for (var attr, name, nName, 
19393ngAttrName, value, isNgAttr, nAttrs = node.attributes,
19394                   j = 0, jj = nAttrs && nAttrs.length; j < jj; j++) {
19395            var attrStartName = false;
vendor: 13,392 bytes, lines 19396-19701
19396            var attrEndName = false;
19397
19398            attr = nAttrs[j];
19399            name = attr.name;
19400            value = attr.value;
19401
19402            // support ngAttr attribute binding
19403            ngAttrName = directiveNormalize(name);
19404            isNgAttr = NG_ATTR_BINDING.test(ngAttrName);
19405            if (isNgAttr) {
19406              name = name.replace(PREFIX_REGEXP, '')
19407                .substr(8).replace(/_(.)/g, function(match, letter) {
19408                  return letter.toUpperCase();
19409                });
19410            }
19411
19412            var multiElementMatch = ngAttrName.match(MULTI_ELEMENT_DIR_RE);
19413            if (multiElementMatch && directiveIsMultiElement(multiElementMatch[1])) {
19414              attrStartName = name;
19415              attrEndName = name.substr(0, name.length - 5) + 'end';
19416              name = name.substr(0, name.length - 6);
19417            }
19418
19419            nName = directiveNormalize(name.toLowerCase());
19420            attrsMap[nName] = name;
19421            if (isNgAttr || !attrs.hasOwnProperty(nName)) {
19422                attrs[nName] = value;
19423                if (getBooleanAttrName(node, nName)) {
19424                  attrs[nName] = true; // presence means true
19425                }
19426            }
19427            addAttrInterpolateDirective(node, directives, value, nName, isNgAttr);
19428            addDirective(directives, nName, 'A', maxPriority, ignoreDirective, attrStartName,
19429                          attrEndName);
19430          }
19431
19432          if (nodeName === 'input' && node.getAttribute('type') === 'hidden') {
19433            // Hidden input elements can have strange behaviour when navigating back to the page
19434            // This tells the browser not to try to cache and reinstate previous values
19435            node.setAttribute('autocomplete', 'off');
19436          }
19437
19438          // use class as directive
19439          if (!cssClassDirectivesEnabled) break;
19440          className = node.className;
19441          if (isObject(className)) {
19442              // Maybe SVGAnimatedString
19443              className = className.animVal;
19444          }
19445          if (isString(className) && className !== '') {
19446            while ((match = CLASS_DIRECTIVE_REGEXP.exec(className))) {
19447              nName = directiveNormalize(match[2]);
19448              if (addDirective(directives, nName, 'C', maxPriority, ignoreDirective)) {
19449                attrs[nName] = trim(match[3]);
19450              }
19451              className = className.substr(match.index + match[0].length);
19452            }
19453          }
19454          break;
19455        case NODE_TYPE_TEXT: /* Text Node */
19456          addTextInterpolateDirective(directives, node.nodeValue);
19457          break;
19458        case NODE_TYPE_COMMENT: /* Comment */
19459          if (!commentDirectivesEnabled) break;
19460          collectCommentDirectives(node, directives, attrs, maxPriority, ignoreDirective);
19461          break;
19462      }
19463
19464      directives.sort(byPriority);
19465      return directives;
19466    }
19467
19468    function collectCommentDirectives(node, directives, attrs, maxPriority, ignoreDirective) {
19469      // function created because of performance, try/catch disables
19470      // the optimization of the whole function #14848
19471      try {
19472        var match = COMMENT_DIRECTIVE_REGEXP.exec(node.nodeValue);
19473        if (match) {
19474          var nName = directiveNormalize(match[1]);
19475          if (addDirective(directives, nName, 'M', maxPriority, ignoreDirective)) {
19476            attrs[nName] = trim(match[2]);
19477          }
19478        }
19479      } catch (e) {
19480        // turns out that under some circumstances IE9 throws errors when one attempts to read
19481        // comment's node value.
19482        // Just ignore it and continue. (Can't seem to reproduce in test case.)
19483      }
19484    }
19485
19486    /**
19487     * Given a node with a directive-start it collects all of the siblings until it finds
19488     * directive-end.
19489     * @param node
19490     * @param attrStart
19491     * @param attrEnd
19492     * @returns {*}
19493     */
19494    function groupScan(node, attrStart, attrEnd) {
19495      var nodes = [];
19496      var depth = 0;
19497      if (attrStart && node.hasAttribute && node.hasAttribute(attrStart)) {
19498        do {
19499          if (!node) {
19500            throw $compileMinErr('uterdir',
19501                      'Unterminated attribute, found \'{0}\' but no matching \'{1}\' found.',
19502                      attrStart, attrEnd);
19503          }
19504          if (node.nodeType === NODE_TYPE_ELEMENT) {
19505            if (node.hasAttribute(attrStart)) depth++;
19506            if (node.hasAttribute(attrEnd)) depth--;
19507          }
19508          nodes.push(node);
19509          node = node.nextSibling;
19510        } while (depth > 0);
19511      } else {
19512        nodes.push(node);
19513      }
19514
19515      return jqLite(nodes);
19516    }
19517
19518    /**
19519     * Wrapper for linking function which converts normal linking function into a grouped
19520     * linking function.
19521     * @param linkFn
19522     * @param attrStart
19523     * @param attrEnd
19524     * @returns {Function}
19525     */
19526    function groupElementsLinkFnWrapper(linkFn, attrStart, attrEnd) {
19527      return function groupedElementsLink(scope, element, attrs, controllers, transcludeFn) {
19528        element = groupScan(element[0], attrStart, attrEnd);
19529        return linkFn(scope, element, attrs, controllers, transcludeFn);
19530      };
19531    }
19532
19533    /**
19534     * A function generator that is used to support both eager and lazy compilation
19535     * linking function.
19536     * @param eager
19537     * @param $compileNodes
19538     * @param transcludeFn
19539     * @param maxPriority
19540     * @param ignoreDirective
19541     * @param previousCompileContext
19542     * @returns {Function}
19543     */
19544    function compilationGenerator(eager, $compileNodes, transcludeFn, maxPriority, ignoreDirective, previousCompileContext) {
19545      var compiled;
19546
19547      if (eager) {
19548        return compile($compileNodes, transcludeFn, maxPriority, ignoreDirective, previousCompileContext);
19549      }
19550      return /** @this */ function lazyCompilation() {
19551        if (!compiled) {
19552          compiled = compile($compileNodes, transcludeFn, maxPriority, ignoreDirective, previousCompileContext);
19553
19554          // Null out all of these references in order to make them eligible for garbage collection
19555          // since this is a potentially long lived closure
19556          $compileNodes = transcludeFn = previousCompileContext = null;
19557        }
19558        return compiled.apply(this, arguments);
19559      };
19560    }
19561
19562    /**
19563     * Once the directives have been collected, their compile functions are executed. This method
19564     * is responsible for inlining directive templates as well as terminating the application
19565     * of the directives if the terminal directive has been reached.
19566     *
19567     * @param {Array} directives Array of collected directives to execute their compile function.
19568     *        this needs to be pre-sorted by priority order.
19569     * @param {Node} compileNode The raw DOM node to apply the compile functions to
19570     * @param {Object} templateAttrs The shared attribute function
19571     * @param {function(angular.Scope, cloneAttachFn=)} transcludeFn A linking function, where the
19572     *                                                  scope argument is auto-generated to the new
19573     *                                                  child of the transcluded parent scope.
19574     * @param {JQLite} jqCollection If we are working on the root of the compile tree then this
19575     *                              argument has the root jqLite array so that we can replace nodes
19576     *                              on it.
19577     * @param {Object=} originalReplaceDirective An optional directive that will be ignored when
19578     *                                           compiling the transclusion.
19579     * @param {Array.<Function>} preLinkFns
19580     * @param {Array.<Function>} postLinkFns
19581     * @param {Object} previousCompileContext Context used for previous compilation of the current
19582     *                                        node
19583     * @returns {Function} linkFn
19584     */
19585    function applyDirectivesToNode(directives, compileNode, templateAttrs, transcludeFn,
19586                                   jqCollection, originalReplaceDirective, preLinkFns, postLinkFns,
19587                                   previousCompileContext) {
19588      previousCompileContext = previousCompileContext || {};
19589
19590      var terminalPriority = -Number.MAX_VALUE,
19591          newScopeDirective = previousCompileContext.newScopeDirective,
19592          controllerDirectives = previousCompileContext.controllerDirectives,
19593          newIsolateScopeDirective = previousCompileContext.newIsolateScopeDirective,
19594          templateDirective = previousCompileContext.templateDirective,
19595          nonTlbTranscludeDirective = previousCompileContext.nonTlbTranscludeDirective,
19596          hasTranscludeDirective = false,
19597          hasTemplate = false,
19598          hasElementTranscludeDirective = previousCompileContext.hasElementTranscludeDirective,
19599          $compileNode = templateAttrs.$$element = jqLite(compileNode),
19600          directive,
19601          directiveName,
19602          $template,
19603          replaceDirective = originalReplaceDirective,
19604          childTranscludeFn = transcludeFn,
19605          linkFn,
19606          didScanForMultipleTransclusion = false,
19607          mightHaveMultipleTransclusionError = false,
19608          directiveValue;
19609
19610      // executes all directives on the current element
19611      for (var i = 0, ii = directives.length; i < ii; i++) {
19612        directive = directives[i];
19613        var attrStart = directive.$$start;
19614        var attrEnd = directive.$$end;
19615
19616        // collect multiblock sections
19617        if (attrStart) {
19618          $compileNode = groupScan(compileNode, attrStart, attrEnd);
19619        }
19620        $template = undefined;
19621
19622        if (terminalPriority > directive.priority) {
19623          break; // prevent further processing of directives
19624        }
19625
19626        directiveValue = directive.scope;
19627
19628        if (directiveValue) {
19629
19630          // skip the check for directives with async templates, we'll check the derived sync
19631          // directive when the template arrives
19632          if (!directive.templateUrl) {
19633            if (isObject(directiveValue)) {
19634              // This directive is trying to add an isolated scope.
19635              // Check that there is no scope of any kind already
19636              assertNoDuplicate('new/isolated scope', newIsolateScopeDirective || newScopeDirective,
19637                                directive, $compileNode);
19638              newIsolateScopeDirective = directive;
19639            } else {
19640              // This directive is trying to add a child scope.
19641              // Check that there is no isolated scope already
19642              assertNoDuplicate('new/isolated scope', newIsolateScopeDirective, directive,
19643                                $compileNode);
19644            }
19645          }
19646
19647          newScopeDirective = newScopeDirective || directive;
19648        }
19649
19650        directiveName = directive.name;
19651
19652        // If we encounter a condition that can result in transclusion on the directive,
19653        // then scan ahead in the remaining directives for others that may cause a multiple
19654        // transclusion error to be thrown during the compilation process.  If a matching directive
19655        // is found, then we know that when we encounter a transcluded directive, we need to eagerly
19656        // compile the `transclude` function rather than doing it lazily in order to throw
19657        // exceptions at the correct time
19658        if (!didScanForMultipleTransclusion && ((directive.replace && (directive.templateUrl || directive.template))
19659            || (directive.transclude && !directive.$$tlb))) {
19660                var candidateDirective;
19661
19662                for (var scanningIndex = i + 1; (candidateDirective = directives[scanningIndex++]);) {
19663                    if ((candidateDirective.transclude && !candidateDirective.$$tlb)
19664                        || (candidateDirective.replace && (candidateDirective.templateUrl || candidateDirective.template))) {
19665                        mightHaveMultipleTransclusionError = true;
19666                        break;
19667                    }
19668                }
19669
19670                didScanForMultipleTransclusion = true;
19671        }
19672
19673        if (!directive.templateUrl && directive.controller) {
19674          controllerDirectives = controllerDirectives || createMap();
19675          assertNoDuplicate('\'' + directiveName + '\' controller',
19676              controllerDirectives[directiveName], directive, $compileNode);
19677          controllerDirectives[directiveName] = directive;
19678        }
19679
19680        directiveValue = directive.transclude;
19681
19682        if (directiveValue) {
19683          hasTranscludeDirective = true;
19684
19685          // Special case ngIf and ngRepeat so that we don't complain about duplicate transclusion.
19686          // This option should only be used by directives that know how to safely handle element transclusion,
19687          // where the transcluded nodes are added or replaced after linking.
19688          if (!directive.$$tlb) {
19689            assertNoDuplicate('transclusion', nonTlbTranscludeDirective, directive, $compileNode);
19690            nonTlbTranscludeDirective = directive;
19691          }
19692
19693          if (directiveValue === 'element') {
19694            hasElementTranscludeDirective = true;
19695            terminalPriority = directive.priority;
19696            $template = $compileNode;
19697            $compileNode = templateAttrs.$$element =
19698                jqLite(compile.$$createComment(directiveName, templateAttrs[directiveName]));
19699            compileNode = $compileNode[0];
19700            replaceWith(jqCollection, sliceArgs($template), compileNode);
19701
19702            // Support: Chrome < 50
19703            // https://github.com/angular/angular.js/issues/14041
19704
19705            // In the versions of V8 prior to Chrome 50, the document fragment that is created
19706            // in the `replaceWith` function is improperly garbage collected despite still
19707            // being referenced by the `parentNode` property of all of the child nodes.  By adding
19708            // a reference to the fragment via a different property, we can avoid that incorrect
19709            // behavior.
19710            // TODO: remove this line after Chrome 50 has been released
19711            $template[0].$$parentNode = $template[0].parentNode;
19712
19713            childTranscludeFn = compilationGenerator(mightHaveMultipleTransclusionError, $template, transcludeFn, terminalPriority,
19714                                        replaceDirective && replaceDirective.name, {
19715                                          // Don't pass in:
19716                                          // - controllerDirectives - otherwise we'll create duplicates controllers
19717                                          // - newIsolateScopeDirective or templateDirective - comb
vendor: 12,814 bytes, lines 19717-19997
19717ining templates with
19718                                          //   element transclusion doesn't make sense.
19719                                          //
19720                                          // We need only nonTlbTranscludeDirective so that we prevent putting transclusion
19721                                          // on the same element more than once.
19722                                          nonTlbTranscludeDirective: nonTlbTranscludeDirective
19723                                        });
19724          } else {
19725
19726            var slots = createMap();
19727
19728            if (!isObject(directiveValue)) {
19729              $template = jqLite(jqLiteClone(compileNode)).contents();
19730            } else {
19731
19732              // We have transclusion slots,
19733              // collect them up, compile them and store their transclusion functions
19734              $template = [];
19735
19736              var slotMap = createMap();
19737              var filledSlots = createMap();
19738
19739              // Parse the element selectors
19740              forEach(directiveValue, function(elementSelector, slotName) {
19741                // If an element selector starts with a ? then it is optional
19742                var optional = (elementSelector.charAt(0) === '?');
19743                elementSelector = optional ? elementSelector.substring(1) : elementSelector;
19744
19745                slotMap[elementSelector] = slotName;
19746
19747                // We explicitly assign `null` since this implies that a slot was defined but not filled.
19748                // Later when calling boundTransclusion functions with a slot name we only error if the
19749                // slot is `undefined`
19750                slots[slotName] = null;
19751
19752                // filledSlots contains `true` for all slots that are either optional or have been
19753                // filled. This is used to check that we have not missed any required slots
19754                filledSlots[slotName] = optional;
19755              });
19756
19757              // Add the matching elements into their slot
19758              forEach($compileNode.contents(), function(node) {
19759                var slotName = slotMap[directiveNormalize(nodeName_(node))];
19760                if (slotName) {
19761                  filledSlots[slotName] = true;
19762                  slots[slotName] = slots[slotName] || [];
19763                  slots[slotName].push(node);
19764                } else {
19765                  $template.push(node);
19766                }
19767              });
19768
19769              // Check for required slots that were not filled
19770              forEach(filledSlots, function(filled, slotName) {
19771                if (!filled) {
19772                  throw $compileMinErr('reqslot', 'Required transclusion slot `{0}` was not filled.', slotName);
19773                }
19774              });
19775
19776              for (var slotName in slots) {
19777                if (slots[slotName]) {
19778                  // Only define a transclusion function if the slot was filled
19779                  slots[slotName] = compilationGenerator(mightHaveMultipleTransclusionError, slots[slotName], transcludeFn);
19780                }
19781              }
19782            }
19783
19784            $compileNode.empty(); // clear contents
19785            childTranscludeFn = compilationGenerator(mightHaveMultipleTransclusionError, $template, transcludeFn, undefined,
19786                undefined, { needsNewScope: directive.$$isolateScope || directive.$$newScope});
19787            childTranscludeFn.$$slots = slots;
19788          }
19789        }
19790
19791        if (directive.template) {
19792          hasTemplate = true;
19793          assertNoDuplicate('template', templateDirective, directive, $compileNode);
19794          templateDirective = directive;
19795
19796          directiveValue = (isFunction(directive.template))
19797              ? directive.template($compileNode, templateAttrs)
19798              : directive.template;
19799
19800          directiveValue = denormalizeTemplate(directiveValue);
19801
19802          if (directive.replace) {
19803            replaceDirective = directive;
19804            if (jqLiteIsTextNode(directiveValue)) {
19805              $template = [];
19806            } else {
19807              $template = removeComments(wrapTemplate(directive.templateNamespace, trim(directiveValue)));
19808            }
19809            compileNode = $template[0];
19810
19811            if ($template.length !== 1 || compileNode.nodeType !== NODE_TYPE_ELEMENT) {
19812              throw $compileMinErr('tplrt',
19813                  'Template for directive \'{0}\' must have exactly one root element. {1}',
19814                  directiveName, '');
19815            }
19816
19817            replaceWith(jqCollection, $compileNode, compileNode);
19818
19819            var newTemplateAttrs = {$attr: {}};
19820
19821            // combine directives from the original node and from the template:
19822            // - take the array of directives for this element
19823            // - split it into two parts, those that already applied (processed) and those that weren't (unprocessed)
19824            // - collect directives from the template and sort them by priority
19825            // - combine directives as: processed + template + unprocessed
19826            var templateDirectives = collectDirectives(compileNode, [], newTemplateAttrs);
19827            var unprocessedDirectives = directives.splice(i + 1, directives.length - (i + 1));
19828
19829            if (newIsolateScopeDirective || newScopeDirective) {
19830              // The original directive caused the current element to be replaced but this element
19831              // also needs to have a new scope, so we need to tell the template directives
19832              // that they would need to get their scope from further up, if they require transclusion
19833              markDirectiveScope(templateDirectives, newIsolateScopeDirective, newScopeDirective);
19834            }
19835            directives = directives.concat(templateDirectives).concat(unprocessedDirectives);
19836            mergeTemplateAttributes(templateAttrs, newTemplateAttrs);
19837
19838            ii = directives.length;
19839          } else {
19840            $compileNode.html(directiveValue);
19841          }
19842        }
19843
19844        if (directive.templateUrl) {
19845          hasTemplate = true;
19846          assertNoDuplicate('template', templateDirective, directive, $compileNode);
19847          templateDirective = directive;
19848
19849          if (directive.replace) {
19850            replaceDirective = directive;
19851          }
19852
19853          // eslint-disable-next-line no-func-assign
19854          nodeLinkFn = compileTemplateUrl(directives.splice(i, directives.length - i), $compileNode,
19855              templateAttrs, jqCollection, hasTranscludeDirective && childTranscludeFn, preLinkFns, postLinkFns, {
19856                controllerDirectives: controllerDirectives,
19857                newScopeDirective: (newScopeDirective !== directive) && newScopeDirective,
19858                newIsolateScopeDirective: newIsolateScopeDirective,
19859                templateDirective: templateDirective,
19860                nonTlbTranscludeDirective: nonTlbTranscludeDirective
19861              });
19862          ii = directives.length;
19863        } else if (directive.compile) {
19864          try {
19865            linkFn = directive.compile($compileNode, templateAttrs, childTranscludeFn);
19866            var context = directive.$$originalDirective || directive;
19867            if (isFunction(linkFn)) {
19868              addLinkFns(null, bind(context, linkFn), attrStart, attrEnd);
19869            } else if (linkFn) {
19870              addLinkFns(bind(context, linkFn.pre), bind(context, linkFn.post), attrStart, attrEnd);
19871            }
19872          } catch (e) {
19873            $exceptionHandler(e, startingTag($compileNode));
19874          }
19875        }
19876
19877        if (directive.terminal) {
19878          nodeLinkFn.terminal = true;
19879          terminalPriority = Math.max(terminalPriority, directive.priority);
19880        }
19881
19882      }
19883
19884      nodeLinkFn.scope = newScopeDirective && newScopeDirective.scope === true;
19885      nodeLinkFn.transcludeOnThisElement = hasTranscludeDirective;
19886      nodeLinkFn.templateOnThisElement = hasTemplate;
19887      nodeLinkFn.transclude = childTranscludeFn;
19888
19889      previousCompileContext.hasElementTranscludeDirective = hasElementTranscludeDirective;
19890
19891      // might be normal or delayed nodeLinkFn depending on if templateUrl is present
19892      return nodeLinkFn;
19893
19894      ////////////////////
19895
19896      function addLinkFns(pre, post, attrStart, attrEnd) {
19897        if (pre) {
19898          if (attrStart) pre = groupElementsLinkFnWrapper(pre, attrStart, attrEnd);
19899          pre.require = directive.require;
19900          pre.directiveName = directiveName;
19901          if (newIsolateScopeDirective === directive || directive.$$isolateScope) {
19902            pre = cloneAndAnnotateFn(pre, {isolateScope: true});
19903          }
19904          preLinkFns.push(pre);
19905        }
19906        if (post) {
19907          if (attrStart) post = groupElementsLinkFnWrapper(post, attrStart, attrEnd);
19908          post.require = directive.require;
19909          post.directiveName = directiveName;
19910          if (newIsolateScopeDirective === directive || directive.$$isolateScope) {
19911            post = cloneAndAnnotateFn(post, {isolateScope: true});
19912          }
19913          postLinkFns.push(post);
19914        }
19915      }
19916
19917      function nodeLinkFn(childLinkFn, scope, linkNode, $rootElement, boundTranscludeFn) {
19918        var i, ii, linkFn, isolateScope, controllerScope, elementControllers, transcludeFn, $element,
19919            attrs, scopeBindingInfo;
19920
19921        if (compileNode === linkNode) {
19922          attrs = templateAttrs;
19923          $element = templateAttrs.$$element;
19924        } else {
19925          $element = jqLite(linkNode);
19926          attrs = new Attributes($element, templateAttrs);
19927        }
19928
19929        controllerScope = scope;
19930        if (newIsolateScopeDirective) {
19931          isolateScope = scope.$new(true);
19932        } else if (newScopeDirective) {
19933          controllerScope = scope.$parent;
19934        }
19935
19936        if (boundTranscludeFn) {
19937          // track `boundTranscludeFn` so it can be unwrapped if `transcludeFn`
19938          // is later passed as `parentBoundTranscludeFn` to `publicLinkFn`
19939          transcludeFn = controllersBoundTransclude;
19940          transcludeFn.$$boundTransclude = boundTranscludeFn;
19941          // expose the slots on the `$transclude` function
19942          transcludeFn.isSlotFilled = function(slotName) {
19943            return !!boundTranscludeFn.$$slots[slotName];
19944          };
19945        }
19946
19947        if (controllerDirectives) {
19948          elementControllers = setupControllers($element, attrs, transcludeFn, controllerDirectives, isolateScope, scope, newIsolateScopeDirective);
19949        }
19950
19951        if (newIsolateScopeDirective) {
19952          // Initialize isolate scope bindings for new isolate scope directive.
19953          compile.$$addScopeInfo($element, isolateScope, true, !(templateDirective && (templateDirective === newIsolateScopeDirective ||
19954              templateDirective === newIsolateScopeDirective.$$originalDirective)));
19955          compile.$$addScopeClass($element, true);
19956          isolateScope.$$isolateBindings =
19957              newIsolateScopeDirective.$$isolateBindings;
19958          scopeBindingInfo = initializeDirectiveBindings(scope, attrs, isolateScope,
19959                                        isolateScope.$$isolateBindings,
19960                                        newIsolateScopeDirective);
19961          if (scopeBindingInfo.removeWatches) {
19962            isolateScope.$on('$destroy', scopeBindingInfo.removeWatches);
19963          }
19964        }
19965
19966        // Initialize bindToController bindings
19967        for (var name in elementControllers) {
19968          var controllerDirective = controllerDirectives[name];
19969          var controller = elementControllers[name];
19970          var bindings = controllerDirective.$$bindings.bindToController;
19971
19972          if (preAssignBindingsEnabled) {
19973            if (bindings) {
19974              controller.bindingInfo =
19975                initializeDirectiveBindings(controllerScope, attrs, controller.instance, bindings, controllerDirective);
19976            } else {
19977              controller.bindingInfo = {};
19978            }
19979
19980            var controllerResult = controller();
19981            if (controllerResult !== controller.instance) {
19982              // If the controller constructor has a return value, overwrite the instance
19983              // from setupControllers
19984              controller.instance = controllerResult;
19985              $element.data('$' + controllerDirective.name + 'Controller', controllerResult);
19986              if (controller.bindingInfo.removeWatches) {
19987                controller.bindingInfo.removeWatches();
19988              }
19989              controller.bindingInfo =
19990                initializeDirectiveBindings(controllerScope, attrs, controller.instance, bindings, controllerDirective);
19991            }
19992          } else {
19993            controller.instance = controller();
19994            $element.data('$' + controllerDirective.name + 'Controller', controller.instance);
19995            controller.bindingInfo =
19996              initializeDirectiveBindings(controllerScope, attrs, controller.instance, bindings, controllerDirective);
19997          }
vendor: 5,779 bytes, lines 19998-20138
19998        }
19999
20000        // Bind the required controllers to the controller, if `require` is an object and `bindToController` is truthy
20001        forEach(controllerDirectives, function(controllerDirective, name) {
20002          var require = controllerDirective.require;
20003          if (controllerDirective.bindToController && !isArray(require) && isObject(require)) {
20004            extend(elementControllers[name].instance, getControllers(name, require, $element, elementControllers));
20005          }
20006        });
20007
20008        // Handle the init and destroy lifecycle hooks on all controllers that have them
20009        forEach(elementControllers, function(controller) {
20010          var controllerInstance = controller.instance;
20011          if (isFunction(controllerInstance.$onChanges)) {
20012            try {
20013              controllerInstance.$onChanges(controller.bindingInfo.initialChanges);
20014            } catch (e) {
20015              $exceptionHandler(e);
20016            }
20017          }
20018          if (isFunction(controllerInstance.$onInit)) {
20019            try {
20020              controllerInstance.$onInit();
20021            } catch (e) {
20022              $exceptionHandler(e);
20023            }
20024          }
20025          if (isFunction(controllerInstance.$doCheck)) {
20026            controllerScope.$watch(function() { controllerInstance.$doCheck(); });
20027            controllerInstance.$doCheck();
20028          }
20029          if (isFunction(controllerInstance.$onDestroy)) {
20030            controllerScope.$on('$destroy', function callOnDestroyHook() {
20031              controllerInstance.$onDestroy();
20032            });
20033          }
20034        });
20035
20036        // PRELINKING
20037        for (i = 0, ii = preLinkFns.length; i < ii; i++) {
20038          linkFn = preLinkFns[i];
20039          invokeLinkFn(linkFn,
20040              linkFn.isolateScope ? isolateScope : scope,
20041              $element,
20042              attrs,
20043              linkFn.require && getControllers(linkFn.directiveName, linkFn.require, $element, elementControllers),
20044              transcludeFn
20045          );
20046        }
20047
20048        // RECURSION
20049        // We only pass the isolate scope, if the isolate directive has a template,
20050        // otherwise the child elements do not belong to the isolate directive.
20051        var scopeToChild = scope;
20052        if (newIsolateScopeDirective && (newIsolateScopeDirective.template || newIsolateScopeDirective.templateUrl === null)) {
20053          scopeToChild = isolateScope;
20054        }
20055        if (childLinkFn) {
20056          childLinkFn(scopeToChild, linkNode.childNodes, undefined, boundTranscludeFn);
20057        }
20058
20059        // POSTLINKING
20060        for (i = postLinkFns.length - 1; i >= 0; i--) {
20061          linkFn = postLinkFns[i];
20062          invokeLinkFn(linkFn,
20063              linkFn.isolateScope ? isolateScope : scope,
20064              $element,
20065              attrs,
20066              linkFn.require && getControllers(linkFn.directiveName, linkFn.require, $element, elementControllers),
20067              transcludeFn
20068          );
20069        }
20070
20071        // Trigger $postLink lifecycle hooks
20072        forEach(elementControllers, function(controller) {
20073          var controllerInstance = controller.instance;
20074          if (isFunction(controllerInstance.$postLink)) {
20075            controllerInstance.$postLink();
20076          }
20077        });
20078
20079        // This is the function that is injected as `$transclude`.
20080        // Note: all arguments are optional!
20081        function controllersBoundTransclude(scope, cloneAttachFn, futureParentElement, slotName) {
20082          var transcludeControllers;
20083          // No scope passed in:
20084          if (!isScope(scope)) {
20085            slotName = futureParentElement;
20086            futureParentElement = cloneAttachFn;
20087            cloneAttachFn = scope;
20088            scope = undefined;
20089          }
20090
20091          if (hasElementTranscludeDirective) {
20092            transcludeControllers = elementControllers;
20093          }
20094          if (!futureParentElement) {
20095            futureParentElement = hasElementTranscludeDirective ? $element.parent() : $element;
20096          }
20097          if (slotName) {
20098            // slotTranscludeFn can be one of three things:
20099            //  * a transclude function - a filled slot
20100            //  * `null` - an optional slot that was not filled
20101            //  * `undefined` - a slot that was not declared (i.e. invalid)
20102            var slotTranscludeFn = boundTranscludeFn.$$slots[slotName];
20103            if (slotTranscludeFn) {
20104              return slotTranscludeFn(scope, cloneAttachFn, transcludeControllers, futureParentElement, scopeToChild);
20105            } else if (isUndefined(slotTranscludeFn)) {
20106              throw $compileMinErr('noslot',
20107               'No parent directive that requires a transclusion with slot name "{0}". ' +
20108               'Element: {1}',
20109               slotName, startingTag($element));
20110            }
20111          } else {
20112            return boundTranscludeFn(scope, cloneAttachFn, transcludeControllers, futureParentElement, scopeToChild);
20113          }
20114        }
20115      }
20116    }
20117
20118    function getControllers(directiveName, require, $element, elementControllers) {
20119      var value;
20120
20121      if (isString(require)) {
20122        var match = require.match(REQUIRE_PREFIX_REGEXP);
20123        var name = require.substring(match[0].length);
20124        var inheritType = match[1] || match[3];
20125        var optional = match[2] === '?';
20126
20127        //If only parents then start at the parent element
20128        if (inheritType === '^^') {
20129          $element = $element.parent();
20130        //Otherwise attempt getting the controller from elementControllers in case
20131        //the element is transcluded (and has no data) and to avoid .data if possible
20132        } else {
20133          value = elementControllers && elementControllers[name];
20134          value = value && value.instance;
20135        }
20136
20137        if (!value) {
20138          var dataName = '$' + name + 'Controller';
20139          value = inheritType ? $element.inheritedData(dataName) : $element.data(dataName);
vendor: 10,984 bytes, lines 20139-20406
20139
20140        }
20141
20142        if (!value && !optional) {
20143          throw $compileMinErr('ctreq',
20144              'Controller \'{0}\', required by directive \'{1}\', can\'t be found!',
20145              name, directiveName);
20146        }
20147      } else if (isArray(require)) {
20148        value = [];
20149        for (var i = 0, ii = require.length; i < ii; i++) {
20150          value[i] = getControllers(directiveName, require[i], $element, elementControllers);
20151        }
20152      } else if (isObject(require)) {
20153        value = {};
20154        forEach(require, function(controller, property) {
20155          value[property] = getControllers(directiveName, controller, $element, elementControllers);
20156        });
20157      }
20158
20159      return value || null;
20160    }
20161
20162    function setupControllers($element, attrs, transcludeFn, controllerDirectives, isolateScope, scope, newIsolateScopeDirective) {
20163      var elementControllers = createMap();
20164      for (var controllerKey in controllerDirectives) {
20165        var directive = controllerDirectives[controllerKey];
20166        var locals = {
20167          $scope: directive === newIsolateScopeDirective || directive.$$isolateScope ? isolateScope : scope,
20168          $element: $element,
20169          $attrs: attrs,
20170          $transclude: transcludeFn
20171        };
20172
20173        var controller = directive.controller;
20174        if (controller === '@') {
20175          controller = attrs[directive.name];
20176        }
20177
20178        var controllerInstance = $controller(controller, locals, true, directive.controllerAs);
20179
20180        // For directives with element transclusion the element is a comment.
20181        // In this case .data will not attach any data.
20182        // Instead, we save the controllers for the element in a local hash and attach to .data
20183        // later, once we have the actual element.
20184        elementControllers[directive.name] = controllerInstance;
20185        $element.data('$' + directive.name + 'Controller', controllerInstance.instance);
20186      }
20187      return elementControllers;
20188    }
20189
20190    // Depending upon the context in which a directive finds itself it might need to have a new isolated
20191    // or child scope created. For instance:
20192    // * if the directive has been pulled into a template because another directive with a higher priority
20193    // asked for element transclusion
20194    // * if the directive itself asks for transclusion but it is at the root of a template and the original
20195    // element was replaced. See https://github.com/angular/angular.js/issues/12936
20196    function markDirectiveScope(directives, isolateScope, newScope) {
20197      for (var j = 0, jj = directives.length; j < jj; j++) {
20198        directives[j] = inherit(directives[j], {$$isolateScope: isolateScope, $$newScope: newScope});
20199      }
20200    }
20201
20202    /**
20203     * looks up the directive and decorates it with exception handling and proper parameters. We
20204     * call this the boundDirective.
20205     *
20206     * @param {string} name name of the directive to look up.
20207     * @param {string} location The directive must be found in specific format.
20208     *   String containing any of theses characters:
20209     *
20210     *   * `E`: element name
20211     *   * `A': attribute
20212     *   * `C`: class
20213     *   * `M`: comment
20214     * @returns {boolean} true if directive was added.
20215     */
20216    function addDirective(tDirectives, name, location, maxPriority, ignoreDirective, startAttrName,
20217                          endAttrName) {
20218      if (name === ignoreDirective) return null;
20219      var match = null;
20220      if (hasDirectives.hasOwnProperty(name)) {
20221        for (var directive, directives = $injector.get(name + Suffix),
20222            i = 0, ii = directives.length; i < ii; i++) {
20223          directive = directives[i];
20224          if ((isUndefined(maxPriority) || maxPriority > directive.priority) &&
20225               directive.restrict.indexOf(location) !== -1) {
20226            if (startAttrName) {
20227              directive = inherit(directive, {$$start: startAttrName, $$end: endAttrName});
20228            }
20229            if (!directive.$$bindings) {
20230              var bindings = directive.$$bindings =
20231                  parseDirectiveBindings(directive, directive.name);
20232              if (isObject(bindings.isolateScope)) {
20233                directive.$$isolateBindings = bindings.isolateScope;
20234              }
20235            }
20236            tDirectives.push(directive);
20237            match = directive;
20238          }
20239        }
20240      }
20241      return match;
20242    }
20243
20244
20245    /**
20246     * looks up the directive and returns true if it is a multi-element directive,
20247     * and therefore requires DOM nodes between -start and -end markers to be grouped
20248     * together.
20249     *
20250     * @param {string} name name of the directive to look up.
20251     * @returns true if directive was registered as multi-element.
20252     */
20253    function directiveIsMultiElement(name) {
20254      if (hasDirectives.hasOwnProperty(name)) {
20255        for (var directive, directives = $injector.get(name + Suffix),
20256            i = 0, ii = directives.length; i < ii; i++) {
20257          directive = directives[i];
20258          if (directive.multiElement) {
20259            return true;
20260          }
20261        }
20262      }
20263      return false;
20264    }
20265
20266    /**
20267     * When the element is replaced with HTML template then the new attributes
20268     * on the template need to be merged with the existing attributes in the DOM.
20269     * The desired effect is to have both of the attributes present.
20270     *
20271     * @param {object} dst destination attributes (original DOM)
20272     * @param {object} src source attributes (from the directive template)
20273     */
20274    function mergeTemplateAttributes(dst, src) {
20275      var srcAttr = src.$attr,
20276          dstAttr = dst.$attr;
20277
20278      // reapply the old attributes to the new element
20279      forEach(dst, function(value, key) {
20280        if (key.charAt(0) !== '$') {
20281          if (src[key] && src[key] !== value) {
20282            if (value.length) {
20283              value += (key === 'style' ? ';' : ' ') + src[key];
20284            } else {
20285              value = src[key];
20286            }
20287          }
20288          dst.$set(key, value, true, srcAttr[key]);
20289        }
20290      });
20291
20292      // copy the new attributes on the old attrs object
20293      forEach(src, function(value, key) {
20294        // Check if we already set this attribute in the loop above.
20295        // `dst` will never contain hasOwnProperty as DOM parser won't let it.
20296        // You will get an "InvalidCharacterError: DOM Exception 5" error if you
20297        // have an attribute like "has-own-property" or "data-has-own-property", etc.
20298        if (!dst.hasOwnProperty(key) && key.charAt(0) !== '$') {
20299          dst[key] = value;
20300
20301          if (key !== 'class' && key !== 'style') {
20302            dstAttr[key] = srcAttr[key];
20303          }
20304        }
20305      });
20306    }
20307
20308
20309    function compileTemplateUrl(directives, $compileNode, tAttrs,
20310        $rootElement, childTranscludeFn, preLinkFns, postLinkFns, previousCompileContext) {
20311      var linkQueue = [],
20312          afterTemplateNodeLinkFn,
20313          afterTemplateChildLinkFn,
20314          beforeTemplateCompileNode = $compileNode[0],
20315          origAsyncDirective = directives.shift(),
20316          derivedSyncDirective = inherit(origAsyncDirective, {
20317            templateUrl: null, transclude: null, replace: null, $$originalDirective: origAsyncDirective
20318          }),
20319          templateUrl = (isFunction(origAsyncDirective.templateUrl))
20320              ? origAsyncDirective.templateUrl($compileNode, tAttrs)
20321              : origAsyncDirective.templateUrl,
20322          templateNamespace = origAsyncDirective.templateNamespace;
20323
20324      $compileNode.empty();
20325
20326      $templateRequest(templateUrl)
20327        .then(function(content) {
20328          var compileNode, tempTemplateAttrs, $template, childBoundTranscludeFn;
20329
20330          content = denormalizeTemplate(content);
20331
20332          if (origAsyncDirective.replace) {
20333            if (jqLiteIsTextNode(content)) {
20334              $template = [];
20335            } else {
20336              $template = removeComments(wrapTemplate(templateNamespace, trim(content)));
20337            }
20338            compileNode = $template[0];
20339
20340            if ($template.length !== 1 || compileNode.nodeType !== NODE_TYPE_ELEMENT) {
20341              throw $compileMinErr('tplrt',
20342                  'Template for directive \'{0}\' must have exactly one root element. {1}',
20343                  origAsyncDirective.name, templateUrl);
20344            }
20345
20346            tempTemplateAttrs = {$attr: {}};
20347            replaceWith($rootElement, $compileNode, compileNode);
20348            var templateDirectives = collectDirectives(compileNode, [], tempTemplateAttrs);
20349
20350            if (isObject(origAsyncDirective.scope)) {
20351              // the original directive that caused the template to be loaded async required
20352              // an isolate scope
20353              markDirectiveScope(templateDirectives, true);
20354            }
20355            directives = templateDirectives.concat(directives);
20356            mergeTemplateAttributes(tAttrs, tempTemplateAttrs);
20357          } else {
20358            compileNode = beforeTemplateCompileNode;
20359            $compileNode.html(content);
20360          }
20361
20362          directives.unshift(derivedSyncDirective);
20363
20364          afterTemplateNodeLinkFn = applyDirectivesToNode(directives, compileNode, tAttrs,
20365              childTranscludeFn, $compileNode, origAsyncDirective, preLinkFns, postLinkFns,
20366              previousCompileContext);
20367          forEach($rootElement, function(node, i) {
20368            if (node === compileNode) {
20369              $rootElement[i] = $compileNode[0];
20370            }
20371          });
20372          afterTemplateChildLinkFn = compileNodes($compileNode[0].childNodes, childTranscludeFn);
20373
20374          while (linkQueue.length) {
20375            var scope = linkQueue.shift(),
20376                beforeTemplateLinkNode = linkQueue.shift(),
20377                linkRootElement = linkQueue.shift(),
20378                boundTranscludeFn = linkQueue.shift(),
20379                linkNode = $compileNode[0];
20380
20381            if (scope.$$destroyed) continue;
20382
20383            if (beforeTemplateLinkNode !== beforeTemplateCompileNode) {
20384              var oldClasses = beforeTemplateLinkNode.className;
20385
20386              if (!(previousCompileContext.hasElementTranscludeDirective &&
20387                  origAsyncDirective.replace)) {
20388                // it was cloned therefore we have to clone as well.
20389                linkNode = jqLiteClone(compileNode);
20390              }
20391              replaceWith(linkRootElement, jqLite(beforeTemplateLinkNode), linkNode);
20392
20393              // Copy in CSS classes from original node
20394              safeAddClass(jqLite(linkNode), oldClasses);
20395            }
20396            if (afterTemplateNodeLinkFn.transcludeOnThisElement) {
20397              childBoundTranscludeFn = createBoundTranscludeFn(scope, afterTemplateNodeLinkFn.transclude, boundTranscludeFn);
20398            } else {
20399              childBoundTranscludeFn = boundTranscludeFn;
20400            }
20401            afterTemplateNodeLinkFn(afterTemplateChildLinkFn, scope, linkNode, $rootElement,
20402              childBoundTranscludeFn);
20403          }
20404          linkQueue = null;
20405        }).catch(function(error) {
20406          if (
vendor: 28,064 bytes, lines 20406-21163
20406error instanceof Error) {
20407            $exceptionHandler(error);
20408          }
20409        });
20410
20411      return function delayedNodeLinkFn(ignoreChildLinkFn, scope, node, rootElement, boundTranscludeFn) {
20412        var childBoundTranscludeFn = boundTranscludeFn;
20413        if (scope.$$destroyed) return;
20414        if (linkQueue) {
20415          linkQueue.push(scope,
20416                         node,
20417                         rootElement,
20418                         childBoundTranscludeFn);
20419        } else {
20420          if (afterTemplateNodeLinkFn.transcludeOnThisElement) {
20421            childBoundTranscludeFn = createBoundTranscludeFn(scope, afterTemplateNodeLinkFn.transclude, boundTranscludeFn);
20422          }
20423          afterTemplateNodeLinkFn(afterTemplateChildLinkFn, scope, node, rootElement, childBoundTranscludeFn);
20424        }
20425      };
20426    }
20427
20428
20429    /**
20430     * Sorting function for bound directives.
20431     */
20432    function byPriority(a, b) {
20433      var diff = b.priority - a.priority;
20434      if (diff !== 0) return diff;
20435      if (a.name !== b.name) return (a.name < b.name) ? -1 : 1;
20436      return a.index - b.index;
20437    }
20438
20439    function assertNoDuplicate(what, previousDirective, directive, element) {
20440
20441      function wrapModuleNameIfDefined(moduleName) {
20442        return moduleName ?
20443          (' (module: ' + moduleName + ')') :
20444          '';
20445      }
20446
20447      if (previousDirective) {
20448        throw $compileMinErr('multidir', 'Multiple directives [{0}{1}, {2}{3}] asking for {4} on: {5}',
20449            previousDirective.name, wrapModuleNameIfDefined(previousDirective.$$moduleName),
20450            directive.name, wrapModuleNameIfDefined(directive.$$moduleName), what, startingTag(element));
20451      }
20452    }
20453
20454
20455    function addTextInterpolateDirective(directives, text) {
20456      var interpolateFn = $interpolate(text, true);
20457      if (interpolateFn) {
20458        directives.push({
20459          priority: 0,
20460          compile: function textInterpolateCompileFn(templateNode) {
20461            var templateNodeParent = templateNode.parent(),
20462                hasCompileParent = !!templateNodeParent.length;
20463
20464            // When transcluding a template that has bindings in the root
20465            // we don't have a parent and thus need to add the class during linking fn.
20466            if (hasCompileParent) compile.$$addBindingClass(templateNodeParent);
20467
20468            return function textInterpolateLinkFn(scope, node) {
20469              var parent = node.parent();
20470              if (!hasCompileParent) compile.$$addBindingClass(parent);
20471              compile.$$addBindingInfo(parent, interpolateFn.expressions);
20472              scope.$watch(interpolateFn, function interpolateFnWatchAction(value) {
20473                node[0].nodeValue = value;
20474              });
20475            };
20476          }
20477        });
20478      }
20479    }
20480
20481
20482    function wrapTemplate(type, template) {
20483      type = lowercase(type || 'html');
20484      switch (type) {
20485      case 'svg':
20486      case 'math':
20487        var wrapper = window.document.createElement('div');
20488        wrapper.innerHTML = '<' + type + '>' + template + '</' + type + '>';
20489        return wrapper.childNodes[0].childNodes;
20490      default:
20491        return template;
20492      }
20493    }
20494
20495
20496    function getTrustedContext(node, attrNormalizedName) {
20497      if (attrNormalizedName === 'srcdoc') {
20498        return $sce.HTML;
20499      }
20500      var tag = nodeName_(node);
20501      // All tags with src attributes require a RESOURCE_URL value, except for
20502      // img and various html5 media tags.
20503      if (attrNormalizedName === 'src' || attrNormalizedName === 'ngSrc') {
20504        if (['img', 'video', 'audio', 'source', 'track'].indexOf(tag) === -1) {
20505          return $sce.RESOURCE_URL;
20506        }
20507      // maction[xlink:href] can source SVG.  It's not limited to <maction>.
20508      } else if (attrNormalizedName === 'xlinkHref' ||
20509          (tag === 'form' && attrNormalizedName === 'action') ||
20510          // links can be stylesheets or imports, which can run script in the current origin
20511          (tag === 'link' && attrNormalizedName === 'href')
20512      ) {
20513        return $sce.RESOURCE_URL;
20514      }
20515    }
20516
20517
20518    function addAttrInterpolateDirective(node, directives, value, name, isNgAttr) {
20519      var trustedContext = getTrustedContext(node, name);
20520      var mustHaveExpression = !isNgAttr;
20521      var allOrNothing = ALL_OR_NOTHING_ATTRS[name] || isNgAttr;
20522
20523      var interpolateFn = $interpolate(value, mustHaveExpression, trustedContext, allOrNothing);
20524
20525      // no interpolation found -> ignore
20526      if (!interpolateFn) return;
20527
20528      if (name === 'multiple' && nodeName_(node) === 'select') {
20529        throw $compileMinErr('selmulti',
20530            'Binding to the \'multiple\' attribute is not supported. Element: {0}',
20531            startingTag(node));
20532      }
20533
20534      if (EVENT_HANDLER_ATTR_REGEXP.test(name)) {
20535        throw $compileMinErr('nodomevents',
20536            'Interpolations for HTML DOM event attributes are disallowed.  Please use the ' +
20537                'ng- versions (such as ng-click instead of onclick) instead.');
20538      }
20539
20540      directives.push({
20541        priority: 100,
20542        compile: function() {
20543            return {
20544              pre: function attrInterpolatePreLinkFn(scope, element, attr) {
20545                var $$observers = (attr.$$observers || (attr.$$observers = createMap()));
20546
20547                // If the attribute has changed since last $interpolate()ed
20548                var newValue = attr[name];
20549                if (newValue !== value) {
20550                  // we need to interpolate again since the attribute value has been updated
20551                  // (e.g. by another directive's compile function)
20552                  // ensure unset/empty values make interpolateFn falsy
20553                  interpolateFn = newValue && $interpolate(newValue, true, trustedContext, allOrNothing);
20554                  value = newValue;
20555                }
20556
20557                // if attribute was updated so that there is no interpolation going on we don't want to
20558                // register any observers
20559                if (!interpolateFn) return;
20560
20561                // initialize attr object so that it's ready in case we need the value for isolate
20562                // scope initialization, otherwise the value would not be available from isolate
20563                // directive's linking fn during linking phase
20564                attr[name] = interpolateFn(scope);
20565
20566                ($$observers[name] || ($$observers[name] = [])).$$inter = true;
20567                (attr.$$observers && attr.$$observers[name].$$scope || scope).
20568                  $watch(interpolateFn, function interpolateFnWatchAction(newValue, oldValue) {
20569                    //special case for class attribute addition + removal
20570                    //so that class changes can tap into the animation
20571                    //hooks provided by the $animate service. Be sure to
20572                    //skip animations when the first digest occurs (when
20573                    //both the new and the old values are the same) since
20574                    //the CSS classes are the non-interpolated values
20575                    if (name === 'class' && newValue !== oldValue) {
20576                      attr.$updateClass(newValue, oldValue);
20577                    } else {
20578                      attr.$set(name, newValue);
20579                    }
20580                  });
20581              }
20582            };
20583          }
20584      });
20585    }
20586
20587
20588    /**
20589     * This is a special jqLite.replaceWith, which can replace items which
20590     * have no parents, provided that the containing jqLite collection is provided.
20591     *
20592     * @param {JqLite=} $rootElement The root of the compile tree. Used so that we can replace nodes
20593     *                               in the root of the tree.
20594     * @param {JqLite} elementsToRemove The jqLite element which we are going to replace. We keep
20595     *                                  the shell, but replace its DOM node reference.
20596     * @param {Node} newNode The new DOM node.
20597     */
20598    function replaceWith($rootElement, elementsToRemove, newNode) {
20599      var firstElementToRemove = elementsToRemove[0],
20600          removeCount = elementsToRemove.length,
20601          parent = firstElementToRemove.parentNode,
20602          i, ii;
20603
20604      if ($rootElement) {
20605        for (i = 0, ii = $rootElement.length; i < ii; i++) {
20606          if ($rootElement[i] === firstElementToRemove) {
20607            $rootElement[i++] = newNode;
20608            for (var j = i, j2 = j + removeCount - 1,
20609                     jj = $rootElement.length;
20610                 j < jj; j++, j2++) {
20611              if (j2 < jj) {
20612                $rootElement[j] = $rootElement[j2];
20613              } else {
20614                delete $rootElement[j];
20615              }
20616            }
20617            $rootElement.length -= removeCount - 1;
20618
20619            // If the replaced element is also the jQuery .context then replace it
20620            // .context is a deprecated jQuery api, so we should set it only when jQuery set it
20621            // http://api.jquery.com/context/
20622            if ($rootElement.context === firstElementToRemove) {
20623              $rootElement.context = newNode;
20624            }
20625            break;
20626          }
20627        }
20628      }
20629
20630      if (parent) {
20631        parent.replaceChild(newNode, firstElementToRemove);
20632      }
20633
20634      // Append all the `elementsToRemove` to a fragment. This will...
20635      // - remove them from the DOM
20636      // - allow them to still be traversed with .nextSibling
20637      // - allow a single fragment.qSA to fetch all elements being removed
20638      var fragment = window.document.createDocumentFragment();
20639      for (i = 0; i < removeCount; i++) {
20640        fragment.appendChild(elementsToRemove[i]);
20641      }
20642
20643      if (jqLite.hasData(firstElementToRemove)) {
20644        // Copy over user data (that includes Angular's $scope etc.). Don't copy private
20645        // data here because there's no public interface in jQuery to do that and copying over
20646        // event listeners (which is the main use of private data) wouldn't work anyway.
20647        jqLite.data(newNode, jqLite.data(firstElementToRemove));
20648
20649        // Remove $destroy event listeners from `firstElementToRemove`
20650        jqLite(firstElementToRemove).off('$destroy');
20651      }
20652
20653      // Cleanup any data/listeners on the elements and children.
20654      // This includes invoking the $destroy event on any elements with listeners.
20655      jqLite.cleanData(fragment.querySelectorAll('*'));
20656
20657      // Update the jqLite collection to only contain the `newNode`
20658      for (i = 1; i < removeCount; i++) {
20659        delete elementsToRemove[i];
20660      }
20661      elementsToRemove[0] = newNode;
20662      elementsToRemove.length = 1;
20663    }
20664
20665
20666    function cloneAndAnnotateFn(fn, annotation) {
20667      return extend(function() { return fn.apply(null, arguments); }, fn, annotation);
20668    }
20669
20670
20671    function invokeLinkFn(linkFn, scope, $element, attrs, controllers, transcludeFn) {
20672      try {
20673        linkFn(scope, $element, attrs, controllers, transcludeFn);
20674      } catch (e) {
20675        $exceptionHandler(e, startingTag($element));
20676      }
20677    }
20678
20679
20680    // Set up $watches for isolate scope and controller bindings.
20681    function initializeDirectiveBindings(scope, attrs, destination, bindings, directive) {
20682      var removeWatchCollection = [];
20683      var initialChanges = {};
20684      var changes;
20685      forEach(bindings, function initializeBinding(definition, scopeName) {
20686        var attrName = definition.attrName,
20687        optional = definition.optional,
20688        mode = definition.mode, // @, =, <, or &
20689        lastValue,
20690        parentGet, parentSet, compare, removeWatch;
20691
20692        switch (mode) {
20693
20694          case '@':
20695            if (!optional && !hasOwnProperty.call(attrs, attrName)) {
20696              destination[scopeName] = attrs[attrName] = undefined;
20697            }
20698            removeWatch = attrs.$observe(attrName, function(value) {
20699              if (isString(value) || isBoolean(value)) {
20700                var oldValue = destination[scopeName];
20701                recordChanges(scopeName, value, oldValue);
20702                destination[scopeName] = value;
20703              }
20704            });
20705            attrs.$$observers[attrName].$$scope = scope;
20706            lastValue = attrs[attrName];
20707            if (isString(lastValue)) {
20708              // If the attribute has been provided then we trigger an interpolation to ensure
20709              // the value is there for use in the link fn
20710              destination[scopeName] = $interpolate(lastValue)(scope);
20711            } else if (isBoolean(lastValue)) {
20712              // If the attributes is one of the BOOLEAN_ATTR then Angular will have converted
20713              // the value to boolean rather than a string, so we special case this situation
20714              destination[scopeName] = lastValue;
20715            }
20716            initialChanges[scopeName] = new SimpleChange(_UNINITIALIZED_VALUE, destination[scopeName]);
20717            removeWatchCollection.push(removeWatch);
20718            break;
20719
20720          case '=':
20721            if (!hasOwnProperty.call(attrs, attrName)) {
20722              if (optional) break;
20723              attrs[attrName] = undefined;
20724            }
20725            if (optional && !attrs[attrName]) break;
20726
20727            parentGet = $parse(attrs[attrName]);
20728            if (parentGet.literal) {
20729              compare = equals;
20730            } else {
20731              // eslint-disable-next-line no-self-compare
20732              compare = function simpleCompare(a, b) { return a === b || (a !== a && b !== b); };
20733            }
20734            parentSet = parentGet.assign || function() {
20735              // reset the change, or we will throw this exception on every $digest
20736              lastValue = destination[scopeName] = parentGet(scope);
20737              throw $compileMinErr('nonassign',
20738                  'Expression \'{0}\' in attribute \'{1}\' used with directive \'{2}\' is non-assignable!',
20739                  attrs[attrName], attrName, directive.name);
20740            };
20741            lastValue = destination[scopeName] = parentGet(scope);
20742            var parentValueWatch = function parentValueWatch(parentValue) {
20743              if (!compare(parentValue, destination[scopeName])) {
20744                // we are out of sync and need to copy
20745                if (!compare(parentValue, lastValue)) {
20746                  // parent changed and it has precedence
20747                  destination[scopeName] = parentValue;
20748                } else {
20749                  // if the parent can be assigned then do so
20750                  parentSet(scope, parentValue = destination[scopeName]);
20751                }
20752              }
20753              lastValue = parentValue;
20754              return lastValue;
20755            };
20756            parentValueWatch.$stateful = true;
20757            if (definition.collection) {
20758              removeWatch = scope.$watchCollection(attrs[attrName], parentValueWatch);
20759            } else {
20760              removeWatch = scope.$watch($parse(attrs[attrName], parentValueWatch), null, parentGet.literal);
20761            }
20762            removeWatchCollection.push(removeWatch);
20763            break;
20764
20765          case '<':
20766            if (!hasOwnProperty.call(attrs, attrName)) {
20767              if (optional) break;
20768              attrs[attrName] = undefined;
20769            }
20770            if (optional && !attrs[attrName]) break;
20771
20772            parentGet = $parse(attrs[attrName]);
20773            var deepWatch = parentGet.literal;
20774
20775            var initialValue = destination[scopeName] = parentGet(scope);
20776            initialChanges[scopeName] = new SimpleChange(_UNINITIALIZED_VALUE, destination[scopeName]);
20777
20778            removeWatch = scope.$watch(parentGet, function parentValueWatchAction(newValue, oldValue) {
20779              if (oldValue === newValue) {
20780                if (oldValue === initialValue || (deepWatch && equals(oldValue, initialValue))) {
20781                  return;
20782                }
20783                oldValue = initialValue;
20784              }
20785              recordChanges(scopeName, newValue, oldValue);
20786              destination[scopeName] = newValue;
20787            }, deepWatch);
20788
20789            removeWatchCollection.push(removeWatch);
20790            break;
20791
20792          case '&':
20793            // Don't assign Object.prototype method to scope
20794            parentGet = attrs.hasOwnProperty(attrName) ? $parse(attrs[attrName]) : noop;
20795
20796            // Don't assign noop to destination if expression is not valid
20797            if (parentGet === noop && optional) break;
20798
20799            destination[scopeName] = function(locals) {
20800              return parentGet(scope, locals);
20801            };
20802            break;
20803        }
20804      });
20805
20806      function recordChanges(key, currentValue, previousValue) {
20807        if (isFunction(destination.$onChanges) && currentValue !== previousValue &&
20808            // eslint-disable-next-line no-self-compare
20809            (currentValue === currentValue || previousValue === previousValue)) {
20810          // If we have not already scheduled the top level onChangesQueue handler then do so now
20811          if (!onChangesQueue) {
20812            scope.$$postDigest(flushOnChangesQueue);
20813            onChangesQueue = [];
20814          }
20815          // If we have not already queued a trigger of onChanges for this controller then do so now
20816          if (!changes) {
20817            changes = {};
20818            onChangesQueue.push(triggerOnChangesHook);
20819          }
20820          // If the has been a change on this property already then we need to reuse the previous value
20821          if (changes[key]) {
20822            previousValue = changes[key].previousValue;
20823          }
20824          // Store this change
20825          changes[key] = new SimpleChange(previousValue, currentValue);
20826        }
20827      }
20828
20829      function triggerOnChangesHook() {
20830        destination.$onChanges(changes);
20831        // Now clear the changes so that we schedule onChanges when more changes arrive
20832        changes = undefined;
20833      }
20834
20835      return {
20836        initialChanges: initialChanges,
20837        removeWatches: removeWatchCollection.length && function removeWatches() {
20838          for (var i = 0, ii = removeWatchCollection.length; i < ii; ++i) {
20839            removeWatchCollection[i]();
20840          }
20841        }
20842      };
20843    }
20844  }];
20845}
20846
20847function SimpleChange(previous, current) {
20848  this.previousValue = previous;
20849  this.currentValue = current;
20850}
20851SimpleChange.prototype.isFirstChange = function() { return this.previousValue === _UNINITIALIZED_VALUE; };
20852
20853
20854var PREFIX_REGEXP = /^((?:x|data)[:\-_])/i;
20855var SPECIAL_CHARS_REGEXP = /[:\-_]+(.)/g;
20856
20857/**
20858 * Converts all accepted directives format into proper directive name.
20859 * @param name Name to normalize
20860 */
20861function directiveNormalize(name) {
20862  return name
20863    .replace(PREFIX_REGEXP, '')
20864    .replace(SPECIAL_CHARS_REGEXP, fnCamelCaseReplace);
20865}
20866
20867/**
20868 * @ngdoc type
20869 * @name $compile.directive.Attributes
20870 *
20871 * @description
20872 * A shared object between directive compile / linking functions which contains normalized DOM
20873 * element attributes. The values reflect current binding state `{{ }}`. The normalization is
20874 * needed since all of these are treated as equivalent in Angular:
20875 *
20876 * ```
20877 *    <span ng:bind="a" ng-bind="a" data-ng-bind="a" x-ng-bind="a">
20878 * ```
20879 */
20880
20881/**
20882 * @ngdoc property
20883 * @name $compile.directive.Attributes#$attr
20884 *
20885 * @description
20886 * A map of DOM element attribute names to the normalized name. This is
20887 * needed to do reverse lookup from normalized name back to actual name.
20888 */
20889
20890
20891/**
20892 * @ngdoc method
20893 * @name $compile.directive.Attributes#$set
20894 * @kind function
20895 *
20896 * @description
20897 * Set DOM element attribute value.
20898 *
20899 *
20900 * @param {string} name Normalized element attribute name of the property to modify. The name is
20901 *          reverse-translated using the {@link ng.$compile.directive.Attributes#$attr $attr}
20902 *          property to the original name.
20903 * @param {string} value Value to set the attribute to. The value can be an interpolated string.
20904 */
20905
20906
20907
20908/**
20909 * Closure compiler type information
20910 */
20911
20912function nodesetLinkingFn(
20913  /* angular.Scope */ scope,
20914  /* NodeList */ nodeList,
20915  /* Element */ rootElement,
20916  /* function(Function) */ boundTranscludeFn
20917) {}
20918
20919function directiveLinkingFn(
20920  /* nodesetLinkingFn */ nodesetLinkingFn,
20921  /* angular.Scope */ scope,
20922  /* Node */ node,
20923  /* Element */ rootElement,
20924  /* function(Function) */ boundTranscludeFn
20925) {}
20926
20927function tokenDifference(str1, str2) {
20928  var values = '',
20929      tokens1 = str1.split(/\s+/),
20930      tokens2 = str2.split(/\s+/);
20931
20932  outer:
20933  for (var i = 0; i < tokens1.length; i++) {
20934    var token = tokens1[i];
20935    for (var j = 0; j < tokens2.length; j++) {
20936      if (token === tokens2[j]) continue outer;
20937    }
20938    values += (values.length > 0 ? ' ' : '') + token;
20939  }
20940  return values;
20941}
20942
20943function removeComments(jqNodes) {
20944  jqNodes = jqLite(jqNodes);
20945  var i = jqNodes.length;
20946
20947  if (i <= 1) {
20948    return jqNodes;
20949  }
20950
20951  while (i--) {
20952    var node = jqNodes[i];
20953    if (node.nodeType === NODE_TYPE_COMMENT ||
20954       (node.nodeType === NODE_TYPE_TEXT && node.nodeValue.trim() === '')) {
20955         splice.call(jqNodes, i, 1);
20956    }
20957  }
20958  return jqNodes;
20959}
20960
20961var $controllerMinErr = minErr('$controller');
20962
20963
20964var CNTRL_REG = /^(\S+)(\s+as\s+([\w$]+))?$/;
20965function identifierForController(controller, ident) {
20966  if (ident && isString(ident)) return ident;
20967  if (isString(controller)) {
20968    var match = CNTRL_REG.exec(controller);
20969    if (match) return match[3];
20970  }
20971}
20972
20973
20974/**
20975 * @ngdoc provider
20976 * @name $controllerProvider
20977 * @this
20978 *
20979 * @description
20980 * The {@link ng.$controller $controller service} is used by Angular to create new
20981 * controllers.
20982 *
20983 * This provider allows controller registration via the
20984 * {@link ng.$controllerProvider#register register} method.
20985 */
20986function $ControllerProvider() {
20987  var controllers = {},
20988      globals = false;
20989
20990  /**
20991   * @ngdoc method
20992   * @name $controllerProvider#has
20993   * @param {string} name Controller name to check.
20994   */
20995  this.has = function(name) {
20996    return controllers.hasOwnProperty(name);
20997  };
20998
20999  /**
21000   * @ngdoc method
21001   * @name $controllerProvider#register
21002   * @param {string|Object} name Controller name, or an object map of controllers where the keys are
21003   *    the names and the values are the constructors.
21004   * @param {Function|Array} constructor Controller constructor fn (optionally decorated with DI
21005   *    annotations in the array notation).
21006   */
21007  this.register = function(name, constructor) {
21008    assertNotHasOwnProperty(name, 'controller');
21009    if (isObject(name)) {
21010      extend(controllers, name);
21011    } else {
21012      controllers[name] = constructor;
21013    }
21014  };
21015
21016  /**
21017   * @ngdoc method
21018   * @name $controllerProvider#allowGlobals
21019   * @description If called, allows `$controller` to find controller constructors on `window`
21020   *
21021   * @deprecated
21022   * sinceVersion="v1.3.0"
21023   * removeVersion="v1.7.0"
21024   * This method of finding controllers has been deprecated.
21025   */
21026  this.allowGlobals = function() {
21027    globals = true;
21028  };
21029
21030
21031  this.$get = ['$injector', '$window', function($injector, $window) {
21032
21033    /**
21034     * @ngdoc service
21035     * @name $controller
21036     * @requires $injector
21037     *
21038     * @param {Function|string} constructor If called with a function then it's considered to be the
21039     *    controller constructor function. Otherwise it's considered to be a string which is used
21040     *    to retrieve the controller constructor using the following steps:
21041     *
21042     *    * check if a controller with given name is registered via `$controllerProvider`
21043     *    * check if evaluating the string on the current scope returns a constructor
21044     *    * if $controllerProvider#allowGlobals, check `window[constructor]` on the global
21045     *      `window` object (deprecated, not recommended)
21046     *
21047     *    The string can use the `controller as property` syntax, where the controller instance is published
21048     *    as the specified property on the `scope`; the `scope` must be injected into `locals` param for this
21049     *    to work correctly.
21050     *
21051     * @param {Object} locals Injection locals for Controller.
21052     * @return {Object} Instance of given controller.
21053     *
21054     * @description
21055     * `$controller` service is responsible for instantiating controllers.
21056     *
21057     * It's just a simple call to {@link auto.$injector $injector}, but extracted into
21058     * a service, so that one can override this service with [BC version](https://gist.github.com/1649788).
21059     */
21060    return function $controller(expression, locals, later, ident) {
21061      // PRIVATE API:
21062      //   param `later` --- indicates that the controller's constructor is invoked at a later time.
21063      //                     If true, $controller will allocate the object with the correct
21064      //                     prototype chain, but will not invoke the controller until a returned
21065      //                     callback is invoked.
21066      //   param `ident` --- An optional label which overrides the label parsed from the controller
21067      //                     expression, if any.
21068      var instance, match, constructor, identifier;
21069      later = later === true;
21070      if (ident && isString(ident)) {
21071        identifier = ident;
21072      }
21073
21074      if (isString(expression)) {
21075        match = expression.match(CNTRL_REG);
21076        if (!match) {
21077          throw $controllerMinErr('ctrlfmt',
21078            'Badly formed controller string \'{0}\'. ' +
21079            'Must match `__name__ as __id__` or `__name__`.', expression);
21080        }
21081        constructor = match[1];
21082        identifier = identifier || match[3];
21083        expression = controllers.hasOwnProperty(constructor)
21084            ? controllers[constructor]
21085            : getter(locals.$scope, constructor, true) ||
21086                (globals ? getter($window, constructor, true) : undefined);
21087
21088        if (!expression) {
21089          throw $controllerMinErr('ctrlreg',
21090            'The controller with the name \'{0}\' is not registered.', constructor);
21091        }
21092
21093        assertArgFn(expression, constructor, true);
21094      }
21095
21096      if (later) {
21097        // Instantiate controller later:
21098        // This machinery is used to create an instance of the object before calling the
21099        // controller's constructor itself.
21100        //
21101        // This allows properties to be added to the controller before the constructor is
21102        // invoked. Primarily, this is used for isolate scope bindings in $compile.
21103        //
21104        // This feature is not intended for use by applications, and is thus not documented
21105        // publicly.
21106        // Object creation: http://jsperf.com/create-constructor/2
21107        var controllerPrototype = (isArray(expression) ?
21108          expression[expression.length - 1] : expression).prototype;
21109        instance = Object.create(controllerPrototype || null);
21110
21111        if (identifier) {
21112          addIdentifier(locals, identifier, instance, constructor || expression.name);
21113        }
21114
21115        return extend(function $controllerInit() {
21116          var result = $injector.invoke(expression, instance, locals, constructor);
21117          if (result !== instance && (isObject(result) || isFunction(result))) {
21118            instance = result;
21119            if (identifier) {
21120              // If result changed, re-assign controllerAs value to scope.
21121              addIdentifier(locals, identifier, instance, constructor || expression.name);
21122            }
21123          }
21124          return instance;
21125        }, {
21126          instance: instance,
21127          identifier: identifier
21128        });
21129      }
21130
21131      instance = $injector.instantiate(expression, locals, constructor);
21132
21133      if (identifier) {
21134        addIdentifier(locals, identifier, instance, constructor || expression.name);
21135      }
21136
21137      return instance;
21138    };
21139
21140    function addIdentifier(locals, identifier, instance, name) {
21141      if (!(locals && isObject(locals.$scope))) {
21142        throw minErr('$controller')('noscp',
21143          'Cannot export controller \'{0}\' as \'{1}\'! No $scope object provided via `locals`.',
21144          name, identifier);
21145      }
21146
21147      locals.$scope[identifier] = instance;
21148    }
21149  }];
21150}
21151
21152/**
21153 * @ngdoc service
21154 * @name $document
21155 * @requires $window
21156 * @this
21157 *
21158 * @description
21159 * A {@link angular.element jQuery or jqLite} wrapper for the browser's `window.document` object.
21160 *
21161 * @example
21162   <example module="documentExample" name="document">
21163     <file name="index.html">
21164       <div ng-controller="ExampleController">
21165         <p>$document title: <b ng-bind="title"></b></p>
21166         <p>window.document title: <b ng-bind="windowTitle"></b></p>
21167       </div>
21168     </file>
21169     <file name="script.js">
21170       angular.module('documentExample', [])
21171         .controller('ExampleController', ['$scope', '$document', function($scope, $document) {
21172           $scope.title = $document[0].title;
21173           $scope.windowTitle = angular.element(window.document)[0].title;
21174         }]);
21175     </file>
21176   </example>
21177 */
21178function $DocumentProvider() {
21179  this.$get = ['$window', function(window) {
21180    return jqLite(window.document);
21181  }];
21182}
21183
21184
21185/**
21186 * @private
21187 * @this
21188 * Listens for document visibility change and makes the current status accessible.
21189 */
21190function $$IsDocumentHiddenProvider() {
21191  this.$get = ['$document', '$rootScope', function($document, $rootScope) {
21192    var doc = $document[0];
21193    var hidden = doc && doc.hidden;
21194
21195    $document.on('visibilitychange', changeListener);
21196
21197    $rootScope.$on('$destroy', function() {
21198      $document.off('visibilitychange', changeListener);
21199    });
21200
21201    function changeListener() {
21202      hidden = doc.hidden;
21203    }
21204
21205    return function() {
21206      return hidden;
21207    };
21208  }];
21209}
21210
21211/**
21212 * @ngdoc service
21213 * @name $exceptionHandler
21214 * @requires ng.$log
21215 * @this
21216 *
21217 * @description
21218 * Any uncaught exception in angular expressions is delegated to this service.
21219 * The default implementation simply delegates to `$log.error` which logs it into
21220 * the browser console.
21221 *
21222 * In unit tests, if `angular-mocks.js` is loaded, this service is overridden by
21223 * {@link ngMock.$exceptionHandler mock $exceptionHandler} which aids in testing.
21224 *
21225 * ## Example:
21226 *
21227 * The example below will overwrite the default `$exceptionHandler` in order to (a) log uncaught
21228 * errors to the backend for later inspection by the developers and (b) to use `$log.warn()` instead
21229 * of `$log.error()`.
21230 *
21231 * ```js
21232 *   angular.
21233 *     module('exceptionOverwrite', []).
21234 *     factory('$exceptionHandler', ['$log', 'logErrorsToBackend', function($log, logErrorsToBackend) {
21235 *       return function myExceptionHandler(exception, cause) {
21236 *         logErrorsToBackend(exception, cause);
21237 *         $log.warn(exception, cause);
21238 *       };
21239 *     }
21239]);
21240 * ```
21241 *
21242 * <hr />
21243 * Note, that code executed in event-listeners (even those registered using jqLite's `on`/`bind`
21244 * methods) does not delegate exceptions to the {@link ng.$exceptionHandler $exceptionHandler}
21245 * (unless executed during a digest).
21246 *
21247 * If you wish, you can manually delegate exceptions, e.g.
21248 * `try { ... } catch(e) { $exceptionHandler(e); }`
21249 *
21250 * @param {Error} exception Exception associated with the error.
21251 * @param {string=} cause Optional information about the context in which
21252 *       the error was thrown.
21253 *
21254 */
21255function $ExceptionHandlerProvider() {
21256  this.$get = ['$log', function($log) {
21257    return function(exception, cause) {
21258      $log.error.apply($log, arguments);
21259    };
21260  }];
21261}
21262
21263var $$ForceReflowProvider = /** @this */ function() {
21264  this.$get = ['$document', function($document) {
21265    return function(domNode) {
21266      //the line below will force the browser to perform a repaint so
21267      //that all the animated elements within the animation frame will
21268      //be properly updated and drawn on screen. This is required to
21269      //ensure that the preparation animation is properly flushed so that
21270      //the active state picks up from there. DO NOT REMOVE THIS LINE.
21271      //DO NOT OPTIMIZE THIS LINE. THE MINIFIER WILL REMOVE IT OTHERWISE WHICH
21272      //WILL RESULT IN AN UNPREDICTABLE BUG THAT IS VERY HARD TO TRACK DOWN AND
21273      //WILL TAKE YEARS AWAY FROM YOUR LIFE.
21274      if (domNode) {
21275        if (!domNode.nodeType && domNode instanceof jqLite) {
21276          domNode = domNode[0];
21277        }
21278      } else {
21279        domNode = $document[0].body;
21280      }
21281      return domNode.offsetWidth + 1;
21282    };
21283  }];
21284};
21285
21286var APPLICATION_JSON = 'application/json';
21287var CONTENT_TYPE_APPLICATION_JSON = {'Content-Type': APPLICATION_JSON + ';charset=utf-8'};
21288var JSON_START = /^\[|^\{(?!\{)/;
21289var JSON_ENDS = {
21290  '[': /]$/,
21291  '{': /}$/
21292};
21293var JSON_PROTECTION_PREFIX = /^\)]\}',?\n/;
21294var $httpMinErr = minErr('$http');
21295
21296function serializeValue(v) {
21297  if (isObject(v)) {
21298    return isDate(v) ? v.toISOString() : toJson(v);
21299  }
21300  return v;
21301}
21302
21303
21304/** @this */
21305function $HttpParamSerializerProvider() {
21306  /**
21307   * @ngdoc service
21308   * @name $httpParamSerializer
21309   * @description
21310   *
21311   * Default {@link $http `$http`} params serializer that converts objects to strings
21312   * according to the following rules:
21313   *
21314   * * `{'foo': 'bar'}` results in `foo=bar`
21315   * * `{'foo': Date.now()}` results in `foo=2015-04-01T09%3A50%3A49.262Z` (`toISOString()` and encoded representation of a Date object)
21316   * * `{'foo': ['bar', 'baz']}` results in `foo=bar&foo=baz` (repeated key for each array element)
21317   * * `{'foo': {'bar':'baz'}}` results in `foo=%7B%22bar%22%3A%22baz%22%7D` (stringified and encoded representation of an object)
21318   *
21319   * Note that serializer will sort the request parameters alphabetically.
21320   * */
21321
21322  this.$get = function() {
21323    return function ngParamSerializer(params) {
21324      if (!params) return '';
21325      var parts = [];
21326      forEachSorted(params, function(value, key) {
21327        if (value === null || isUndefined(value)) return;
21328        if (isArray(value)) {
21329          forEach(value, function(v) {
21330            parts.push(encodeUriQuery(key)  + '=' + encodeUriQuery(serializeValue(v)));
21331          });
21332        } else {
21333          parts.push(encodeUriQuery(key) + '=' + encodeUriQuery(serializeValue(value)));
21334        }
21335      });
21336
21337      return parts.join('&');
21338    };
21339  };
21340}
21341
21342/** @this */
21343function $HttpParamSerializerJQLikeProvider() {
21344  /**
21345   * @ngdoc service
21346   * @name $httpParamSerializerJQLike
21347   *
21348   * @description
21349   *
21350   * Alternative {@link $http `$http`} params serializer that follows
21351   * jQuery's [`param()`](http://api.jquery.com/jquery.param/) method logic.
21352   * The serializer will also sort the params alphabetically.
21353   *
21354   * To use it for serializing `$http` request parameters, set it as the `paramSerializer` property:
21355   *
21356   * ```js
21357   * $http({
21358   *   url: myUrl,
21359   *   method: 'GET',
21360   *   params: myParams,
21361   *   paramSerializer: '$httpParamSerializerJQLike'
21362   * });
21363   * ```
21364   *
21365   * It is also possible to set it as the default `paramSerializer` in the
21366   * {@link $httpProvider#defaults `$httpProvider`}.
21367   *
21368   * Additionally, you can inject the serializer and use it explicitly, for example to serialize
21369   * form data for submission:
21370   *
21371   * ```js
21372   * .controller(function($http, $httpParamSerializerJQLike) {
21373   *   //...
21374   *
21375   *   $http({
21376   *     url: myUrl,
21377   *     method: 'POST',
21378   *     data: $httpParamSerializerJQLike(myData),
21379   *     headers: {
21380   *       'Content-Type': 'application/x-www-form-urlencoded'
21381   *     }
21382   *   });
21383   *
21384   * });
21385   * ```
21386   *
21387   * */
21388  this.$get = function() {
21389    return function jQueryLikeParamSerializer(params) {
21390      if (!params) return '';
21391      var parts = [];
21392      serialize(params, '', true);
21393      return parts.join('&');
21394
21395      function serialize(toSerialize, prefix, topLevel) {
21396        if (toSerialize === null || isUndefined(toSerialize)) return;
21397        if (isArray(toSerialize)) {
vendor: 6,108 bytes, lines 21398-21599
21398          forEach(toSerialize, function(value, index) {
21399            serialize(value, prefix + '[' + (isObject(value) ? index : '') + ']');
21400          });
21401        } else if (isObject(toSerialize) && !isDate(toSerialize)) {
21402          forEachSorted(toSerialize, function(value, key) {
21403            serialize(value, prefix +
21404                (topLevel ? '' : '[') +
21405                key +
21406                (topLevel ? '' : ']'));
21407          });
21408        } else {
21409          parts.push(encodeUriQuery(prefix) + '=' + encodeUriQuery(serializeValue(toSerialize)));
21410        }
21411      }
21412    };
21413  };
21414}
21415
21416function defaultHttpResponseTransform(data, headers) {
21417  if (isString(data)) {
21418    // Strip json vulnerability protection prefix and trim whitespace
21419    var tempData = data.replace(JSON_PROTECTION_PREFIX, '').trim();
21420
21421    if (tempData) {
21422      var contentType = headers('Content-Type');
21423      if ((contentType && (contentType.indexOf(APPLICATION_JSON) === 0)) || isJsonLike(tempData)) {
21424        data = fromJson(tempData);
21425      }
21426    }
21427  }
21428
21429  return data;
21430}
21431
21432function isJsonLike(str) {
21433    var jsonStart = str.match(JSON_START);
21434    return jsonStart && JSON_ENDS[jsonStart[0]].test(str);
21435}
21436
21437/**
21438 * Parse headers into key value object
21439 *
21440 * @param {string} headers Raw headers as a string
21441 * @returns {Object} Parsed headers as key value object
21442 */
21443function parseHeaders(headers) {
21444  var parsed = createMap(), i;
21445
21446  function fillInParsed(key, val) {
21447    if (key) {
21448      parsed[key] = parsed[key] ? parsed[key] + ', ' + val : val;
21449    }
21450  }
21451
21452  if (isString(headers)) {
21453    forEach(headers.split('\n'), function(line) {
21454      i = line.indexOf(':');
21455      fillInParsed(lowercase(trim(line.substr(0, i))), trim(line.substr(i + 1)));
21456    });
21457  } else if (isObject(headers)) {
21458    forEach(headers, function(headerVal, headerKey) {
21459      fillInParsed(lowercase(headerKey), trim(headerVal));
21460    });
21461  }
21462
21463  return parsed;
21464}
21465
21466
21467/**
21468 * Returns a function that provides access to parsed headers.
21469 *
21470 * Headers are lazy parsed when first requested.
21471 * @see parseHeaders
21472 *
21473 * @param {(string|Object)} headers Headers to provide access to.
21474 * @returns {function(string=)} Returns a getter function which if called with:
21475 *
21476 *   - if called with an argument returns a single header value or null
21477 *   - if called with no arguments returns an object containing all headers.
21478 */
21479function headersGetter(headers) {
21480  var headersObj;
21481
21482  return function(name) {
21483    if (!headersObj) headersObj =  parseHeaders(headers);
21484
21485    if (name) {
21486      var value = headersObj[lowercase(name)];
21487      if (value === undefined) {
21488        value = null;
21489      }
21490      return value;
21491    }
21492
21493    return headersObj;
21494  };
21495}
21496
21497
21498/**
21499 * Chain all given functions
21500 *
21501 * This function is used for both request and response transforming
21502 *
21503 * @param {*} data Data to transform.
21504 * @param {function(string=)} headers HTTP headers getter fn.
21505 * @param {number} status HTTP status code of the response.
21506 * @param {(Function|Array.<Function>)} fns Function or an array of functions.
21507 * @returns {*} Transformed data.
21508 */
21509function transformData(data, headers, status, fns) {
21510  if (isFunction(fns)) {
21511    return fns(data, headers, status);
21512  }
21513
21514  forEach(fns, function(fn) {
21515    data = fn(data, headers, status);
21516  });
21517
21518  return data;
21519}
21520
21521
21522function isSuccess(status) {
21523  return 200 <= status && status < 300;
21524}
21525
21526
21527/**
21528 * @ngdoc provider
21529 * @name $httpProvider
21530 * @this
21531 *
21532 * @description
21533 * Use `$httpProvider` to change the default behavior of the {@link ng.$http $http} service.
21534 * */
21535function $HttpProvider() {
21536  /**
21537   * @ngdoc property
21538   * @name $httpProvider#defaults
21539   * @description
21540   *
21541   * Object containing default values for all {@link ng.$http $http} requests.
21542   *
21543   * - **`defaults.cache`** - {boolean|Object} - A boolean value or object created with
21544   * {@link ng.$cacheFactory `$cacheFactory`} to enable or disable caching of HTTP responses
21545   * by default. See {@link $http#caching $http Caching} for more information.
21546   *
21547   * - **`defaults.xsrfCookieName`** - {string} - Name of cookie containing the XSRF token.
21548   * Defaults value is `'XSRF-TOKEN'`.
21549   *
21550   * - **`defaults.xsrfHeaderName`** - {string} - Name of HTTP header to populate with the
21551   * XSRF token. Defaults value is `'X-XSRF-TOKEN'`.
21552   *
21553   * - **`defaults.headers`** - {Object} - Default headers for all $http requests.
21554   * Refer to {@link ng.$http#setting-http-headers $http} for documentation on
21555   * setting default headers.
21556   *     - **`defaults.headers.common`**
21557   *     - **`defaults.headers.post`**
21558   *     - **`defaults.headers.put`**
21559   *     - **`defaults.headers.patch`**
21560   *
21561   *
21562   * - **`defaults.paramSerializer`** - `{string|function(Object<string,string>):string}` - A function
21563   *  used to the prepare string representation of request parameters (specified as an object).
21564   *  If specified as string, it is interpreted as a function registered with the {@link auto.$injector $injector}.
21565   *  Defaults to {@link ng.$httpParamSerializer $httpParamSerializer}.
21566   *
21567   * - **`defaults.jsonpCallbackParam`** - `{string}` - the name of the query parameter that passes the name of the
21568   * callback in a JSONP request. The value of this parameter will be replaced with the expression generated by the
21569   * {@link $jsonpCallbacks} service. Defaults to `'callback'`.
21570   *
21571   **/
21572  var defaults = this.defaults = {
21573    // transform incoming response data
21574    transformResponse: [defaultHttpResponseTransform],
21575
21576    // transform outgoing request data
21577    transformRequest: [function(d) {
21578      return isObject(d) && !isFile(d) && !isBlob(d) && !isFormData(d) ? toJson(d) : d;
21579    }],
21580
21581    // default headers
21582    headers: {
21583      common: {
21584        'Accept': 'application/json, text/plain, */*'
21585      },
21586      post:   shallowCopy(CONTENT_TYPE_APPLICATION_JSON),
21587      put:    shallowCopy(CONTENT_TYPE_APPLICATION_JSON),
21588      patch:  shallowCopy(CONTENT_TYPE_APPLICATION_JSON)
21589    },
21590
21591    xsrfCookieName: 'XSRF-TOKEN',
21592    xsrfHeaderName: 'X-XSRF-TOKEN',
21593
21594    paramSerializer: '$httpParamSerializer',
21595
21596    jsonpCallbackParam: 'callback'
21597  };
21598
21599  var useApplyAsync = false;
21600  /**
21601   * @ngdoc method
21602   * @name $httpProvider#useApplyAsync
21603   * @description
21604   *
21605   * Configure $http service to combine processing of multiple http responses received at around
21606   * the same time via {@link ng.$rootScope.Scope#$applyAsync $rootScope.$applyAsync}. This can result in
21607   * significant performance improvement for bigger applications that make many HTTP requests
21608   * concurrently (common during application bootstrap).
21609   *
21610   * Defaults to false. If no value is specified, returns the current configured value.
21611   *
21612   * @param {boolean=} value If true, when requests are loaded, they will schedule a deferred
21613   *    "apply" on the next tick, giving time for subsequent requests in a roughly ~10ms window
21614   *    to load and share the same digest cycle.
21615   *
21616   * @returns {boolean|Object} If a value is specified, returns the $httpProvider for chaining.
21617   *    otherwise, returns the current configured value.
21618   **/
21619  this.useApplyAsync = function(value) {
21620    if (isDefined(value)) {
21621      useApplyAsync = !!value;
21622      return this;
21623    }
21624    return useApplyAsync;
21625  };
21626
21627  /**
21628   * @ngdoc property
21629   * @name $httpProvider#interceptors
21630   * @description
21631   *
21632   * Array containing service factories for all synchronous or asynchronous {@link ng.$http $http}
21633   * pre-processing of request or postprocessing of responses.
21634   *
21635   * These service factories are ordered by request, i.e. they are applied in the same order as the
21636   * array, on request, but reverse order, on response.
21637   *
21638   * {@link ng.$http#interceptors Interceptors detailed info}
21639   **/
21640  var interceptorFactories = this.interceptors = [];
21641
21642  this.$get = ['$browser', '$httpBackend', '$$cookieReader', '$cacheFactory', '$rootScope', '$q', '$injector', '$sce',
21643      function($browser, $httpBackend, $$cookieReader, $cacheFactory, $rootScope, $q, $injector, $sce) {
21644
21645    var defaultCache = $cacheFactory('$http');
21646
21647    /**
21648     * Make sure that default param serializer is exposed as a function
21649     */
21650    defaults.paramSerializer = isString(defaults.paramSerializer) ?
21651      $injector.get(defaults.paramSerializer) : defaults.paramSerializer;
21652
21653    /**
21654     * Interceptors stored in reverse order. Inner interceptors before outer interceptors.
21655     * The reversal is needed so that we can build up the interception chain around the
21656     * server request.
21657     */
21658    var reversedInterceptors = [];
21659
21660    forEach(interceptorFactories, function(interceptorFactory) {
21661      reversedInterceptors.unshift(isString(interceptorFactory)
21662          ? $injector.get(interceptorFactory) : $injector.invoke(interceptorFactory));
21663    });
21664
21665    /**
21666     * @ngdoc service
21667     * @kind function
21668     * @name $http
21669     * @requires ng.$httpBackend
21670     * @requires $cacheFactory
21671     * @requires $rootScope
21672     * @requires $q
21673     * @requires $injector
21674     *
21675     * @description
21676     * The `$http` service is a core Angular service that facilitates communication with the remote
21677     * HTTP servers via the browser's [XMLHttpRequest](https://developer.mozilla.org/en/xmlhttprequest)
21678     * object or via [JSONP](http://en.wikipedia.org/wiki/JSONP).
21679     *
21680     * For unit testing applications that use `$http` service, see
21681     * {@link ngMock.$httpBackend $httpBackend mock}.
21682     *
21683     * For a higher level of abstraction, please check out the {@link ngResource.$resource
21684     * $resource} service.
21685     *
21686     * The $http API is based on the {@link ng.$q deferred/promise APIs} exposed by
21687     * the $q service. While for simple usage patterns this doesn't matter much, for advanced usage
21688     * it is important to familiarize yourself with these APIs and the guarantees they provide.
21689     *
21690     *
21691     * ## General usage
21692     * The `$http` service is a function which takes a single argument — a {@link $http#usage configuration object} —
21693     * that is used to generate an HTTP request and returns  a {@link ng.$q promise}.
21694     *
21695     * ```js
21696     *   // Simple GET request example:
21697     *   $http({
21698     *     method: 'GET',
21699     *     url: '/someUrl'
21700     *   }).then(function successCallback(response) {
21701     *       // this callback will be called asynchronously
21702     *       // when the response is available
21703     *     }, function errorCallback(response) {
21704     *       // called asynchronously if an error occurs
21705     *       // or server returns response with an error status.
21706     *     });
21707     * ```
21708     *
21709     * The response object has these properties:
21710     *
21711     *   - **data** – `{string|Object}` – The response body transformed with the transform
21712     *     functions.
21713     *   - **status** – `{number}` – HTTP status code of the response.
21714     *   - **headers** – `{function([headerName])}` – Header getter function.
21715     *   - **config** – `{Object}` – The configuration object that was used to generate the request.
21716     *   - **statusText** – `{string}` – HTTP status text of the response.
21717     *
21718     * A response status code between 200 and 299 is considered a success status and will result in
21719     * the success callback being called. Any response status code outside of that range is
21720     * considered an error status and will result in the error callback being called.
21721     * Also, status codes less than -1 are normalized to zero. -1 usually means the request was
21722     * aborted, e.g. using a `config.timeout`.
21723     * Note that if the response is a redirect, XMLHttpRequest will transparently follow it, meaning
21724     * that the outcome (success or error) will be determined by the final response status code.
21725     *
21726     *
21727     * ## Shortcut methods
21728     *
21729     * Shortcut methods are also available. All shortcut methods require passing in the URL, and
21730     * request data must be passed in for POST/PUT requests. An optional config can be passed as the
21731     * last argument.
21732     *
21733     * ```js
21734     *   $http.get('/someUrl', config).then(successCallback, errorCallback);
21735     *   $http.post('/someUrl', data, config).then(successCallback, errorCallback);
21736     * ```
21737     *
21738     * Complete list of shortcut methods:
21739     *
21740     * - {@link ng.$http#get $http.get}
21741     * - {@link ng.$http#head $http.head}
21742     * - {@link ng.$http#post $http.post}
21743     * - {@link ng.$http#put $http.put}
21744     * - {@link ng.$http#delete $http.delete}
21745     * - {@link ng.$http#jsonp $http.jsonp}
21746     * - {@link ng.$http#patch $http.patch}
21747     *
21748     *
21749     * ## Writing Unit Tests that use $http
21750     * When unit testing (using {@link ngMock ngMock}), it is necessary to call
21751     * {@link ngMock.$httpBackend#flush $httpBackend.flush()} to flush each pending
21752     * request using trained responses.
21753     *
21754     * ```
21755     * $httpBackend.expectGET(...);
21756     * $http.get(...);
21757     * $httpBackend.flush();
21758     * ```
21759     *
21760     * ## Setting HTTP Headers
21761     *
21762     * The $http service will automatically add certain HTTP headers to all requests. These defaults
21763     * can be fully configured by accessing the `$httpProvider.defaults.headers` configuration
21764     * object, which currently contains this default configuration:
21765     *
21766     * - `$httpProvider.defaults.headers.common` (headers that are common for all requests):
21767     *   - <code>Accept: application/json, text/plain, \*&#65279;/&#65279;\*</code>
21768     * - `$httpProvider.defaults.headers.post`: (header defaults for POST requests)
21769     *   - `Content-Type: application/json`
21770     * - `$httpProvider.defaults.headers.put` (header defaults for PUT requests)
21771     *   - `Content-Type: application/json`
21772     *
21773     * To add or overwrite these defaults, simply add or remove a property from these configuration
21774     * objects. To add headers for an HTTP method other than POST or PUT, simply add a new object
21775     * with the lowercased HTTP method name as the key, e.g.
21776     * `$httpProvider.defaults.headers.get = { 'My-Header' : 'value' }`.
21777     *
21778     * The defaults can also be set at runtime via the `$http.defaults` object in the same
21779     * fashion. For example:
21780     *
21781     * ```
21782     * module.run(function($http) {
21783     *   $http.defaults.headers.common.Authorization = 'Basic YmVlcDpib29w';
21784     * });
21785     * ```
21786     *
21787     * In addition, you can supply a `headers` property in the config object passed when
21788     * calling `$http(config)`, which overrides the defaults without changing them globally.
21789     *
21790     * To explicitly remove a header automatically added via $httpProvider.defaults.headers on a per request basis,
21791     * Use the `headers` property, setting the desired header to `undefined`. For example:
21792     *
21793     * ```js
21794     * var req = {
21795     *  method: 'POST',
21796     *  url: 'http://example.com',
21797     *  headers: {
21798     *    'Content-Type': undefined
21799     *  },
21800     *  data: { test: 'test' }
21801     * }
21802     *
21803     * $http(req).then(function(){...}, function(){...});
21804     * ```
21805     *
21806     * ## Transforming Requests and Responses
21807     *
21808     * Both requests and responses can be transformed using transformation functions: `transformRequest`
21809     * and `transformResponse`. These properties can be a single function that returns
21810     * the transformed value (`function(data, headersGetter, status)`) or an array of such transformation functions,
21811     * which allows you to `push` or `unshift` a new transformation function into the transformation chain.
21812     *
21813     * <div class="alert alert-warning">
21814     * **Note:** Angular does not make a copy of the `data` parameter before it is passed into the `transformRequest` pipeline.
21815     * That means changes to the properties of `data` are not local to the transform function (since Javascript passes objects by reference).
21816     * For example, when calling `$http.get(url, $scope.myObject)`, modifications to the object's properties in a transformRequest
21817     * function will be reflected on the scope and in any templates where the object is data-bound.
21818     * To prevent this, transform functions should have no side-effects.
21819     * If you need to modify properties, it is recommended to make a copy of the data, or create new object to return.
21820     * </div>
21821     *
21822     * ### Default Transformations
21823     *
21824     * The `$httpProvider` provider and `$http` service expose `defaults.transformRequest` and
21825     * `defaults.transformResponse` properties. If a request does not provide its own transformations
21826     * then these will be applied.
21827     *
21828     * You can augment or replace the default transformations by modifying these properties by adding to or
21829     * replacing the array.
21830     *
21831     * Angular provides the following default transformations:
21832     *
21833     * Request transformations (`$httpProvider.defaults.transformRequest` and `$http.defaults.transformRequest`):
21834     *
21835     * - If the `data` property of the request configuration object contains an object, serialize it
21836     *   into JSON format.
21837     *
21838     * Response transformations (`$httpProvider.defaults.transformResponse` and `$http.defaults.transformResponse`):
21839     *
21840     *  - If XSRF prefix is detected, strip it (see Security Considerations section below).
21841     *  - If JSON response is detected,
vendor: 7,183 bytes, lines 21841-22001
21841 deserialize it using a JSON parser.
21842     *
21843     *
21844     * ### Overriding the Default Transformations Per Request
21845     *
21846     * If you wish to override the request/response transformations only for a single request then provide
21847     * `transformRequest` and/or `transformResponse` properties on the configuration object passed
21848     * into `$http`.
21849     *
21850     * Note that if you provide these properties on the config object the default transformations will be
21851     * overwritten. If you wish to augment the default transformations then you must include them in your
21852     * local transformation array.
21853     *
21854     * The following code demonstrates adding a new response transformation to be run after the default response
21855     * transformations have been run.
21856     *
21857     * ```js
21858     * function appendTransform(defaults, transform) {
21859     *
21860     *   // We can't guarantee that the default transformation is an array
21861     *   defaults = angular.isArray(defaults) ? defaults : [defaults];
21862     *
21863     *   // Append the new transformation to the defaults
21864     *   return defaults.concat(transform);
21865     * }
21866     *
21867     * $http({
21868     *   url: '...',
21869     *   method: 'GET',
21870     *   transformResponse: appendTransform($http.defaults.transformResponse, function(value) {
21871     *     return doTransform(value);
21872     *   })
21873     * });
21874     * ```
21875     *
21876     *
21877     * ## Caching
21878     *
21879     * {@link ng.$http `$http`} responses are not cached by default. To enable caching, you must
21880     * set the config.cache value or the default cache value to TRUE or to a cache object (created
21881     * with {@link ng.$cacheFactory `$cacheFactory`}). If defined, the value of config.cache takes
21882     * precedence over the default cache value.
21883     *
21884     * In order to:
21885     *   * cache all responses - set the default cache value to TRUE or to a cache object
21886     *   * cache a specific response - set config.cache value to TRUE or to a cache object
21887     *
21888     * If caching is enabled, but neither the default cache nor config.cache are set to a cache object,
21889     * then the default `$cacheFactory("$http")` object is used.
21890     *
21891     * The default cache value can be set by updating the
21892     * {@link ng.$http#defaults `$http.defaults.cache`} property or the
21893     * {@link $httpProvider#defaults `$httpProvider.defaults.cache`} property.
21894     *
21895     * When caching is enabled, {@link ng.$http `$http`} stores the response from the server using
21896     * the relevant cache object. The next time the same request is made, the response is returned
21897     * from the cache without sending a request to the server.
21898     *
21899     * Take note that:
21900     *
21901     *   * Only GET and JSONP requests are cached.
21902     *   * The cache key is the request URL including search parameters; headers are not considered.
21903     *   * Cached responses are returned asynchronously, in the same way as responses from the server.
21904     *   * If multiple identical requests are made using the same cache, which is not yet populated,
21905     *     one request will be made to the server and remaining requests will return the same response.
21906     *   * A cache-control header on the response does not affect if or how responses are cached.
21907     *
21908     *
21909     * ## Interceptors
21910     *
21911     * Before you start creating interceptors, be sure to understand the
21912     * {@link ng.$q $q and deferred/promise APIs}.
21913     *
21914     * For purposes of global error handling, authentication, or any kind of synchronous or
21915     * asynchronous pre-processing of request or postprocessing of responses, it is desirable to be
21916     * able to intercept requests before they are handed to the server and
21917     * responses before they are handed over to the application code that
21918     * initiated these requests. The interceptors leverage the {@link ng.$q
21919     * promise APIs} to fulfill this need for both synchronous and asynchronous pre-processing.
21920     *
21921     * The interceptors are service factories that are registered with the `$httpProvider` by
21922     * adding them to the `$httpProvider.interceptors` array. The factory is called and
21923     * injected with dependencies (if specified) and returns the interceptor.
21924     *
21925     * There are two kinds of interceptors (and two kinds of rejection interceptors):
21926     *
21927     *   * `request`: interceptors get called with a http {@link $http#usage config} object. The function is free to
21928     *     modify the `config` object or create a new one. The function needs to return the `config`
21929     *     object directly, or a promise containing the `config` or a new `config` object.
21930     *   * `requestError`: interceptor gets called when a previous interceptor threw an error or
21931     *     resolved with a rejection.
21932     *   * `response`: interceptors get called with http `response` object. The function is free to
21933     *     modify the `response` object or create a new one. The function needs to return the `response`
21934     *     object directly, or as a promise containing the `response` or a new `response` object.
21935     *   * `responseError`: interceptor gets called when a previous interceptor threw an error or
21936     *     resolved with a rejection.
21937     *
21938     *
21939     * ```js
21940     *   // register the interceptor as a service
21941     *   $provide.factory('myHttpInterceptor', function($q, dependency1, dependency2) {
21942     *     return {
21943     *       // optional method
21944     *       'request': function(config) {
21945     *         // do something on success
21946     *         return config;
21947     *       },
21948     *
21949     *       // optional method
21950     *      'requestError': function(rejection) {
21951     *         // do something on error
21952     *         if (canRecover(rejection)) {
21953     *           return responseOrNewPromise
21954     *         }
21955     *         return $q.reject(rejection);
21956     *       },
21957     *
21958     *
21959     *
21960     *       // optional method
21961     *       'response': function(response) {
21962     *         // do something on success
21963     *         return response;
21964     *       },
21965     *
21966     *       // optional method
21967     *      'responseError': function(rejection) {
21968     *         // do something on error
21969     *         if (canRecover(rejection)) {
21970     *           return responseOrNewPromise
21971     *         }
21972     *         return $q.reject(rejection);
21973     *       }
21974     *     };
21975     *   });
21976     *
21977     *   $httpProvider.interceptors.push('myHttpInterceptor');
21978     *
21979     *
21980     *   // alternatively, register the interceptor via an anonymous factory
21981     *   $httpProvider.interceptors.push(function($q, dependency1, dependency2) {
21982     *     return {
21983     *      'request': function(config) {
21984     *          // same as above
21985     *       },
21986     *
21987     *       'response': function(response) {
21988     *          // same as above
21989     *       }
21990     *     };
21991     *   });
21992     * ```
21993     *
21994     * ## Security Considerations
21995     *
21996     * When designing web applications, consider security threats from:
21997     *
21998     * - [JSON vulnerability](http://haacked.com/archive/2008/11/20/anatomy-of-a-subtle-json-vulnerability.aspx)
21999     * - [XSRF](http://en.wikipedia.org/wiki/Cross-site_request_forgery)
22000     *
22001     * Both server and the client must cooperate in order to eliminate these threats. Angular
22001 comes
22002     * pre-configured with strategies that address these issues, but for this to work backend server
22003     * cooperation is required.
22004     *
22005     * ### JSON Vulnerability Protection
22006     *
22007     * A [JSON vulnerability](http://haacked.com/archive/2008/11/20/anatomy-of-a-subtle-json-vulnerability.aspx)
22008     * allows third party website to turn your JSON resource URL into
22009     * [JSONP](http://en.wikipedia.org/wiki/JSONP) request under some conditions. To
22010     * counter this your server can prefix all JSON requests with following string `")]}',\n"`.
22011     * Angular will automatically strip the prefix before processing it as JSON.
22012     *
22013     * For example if your server needs to return:
22014     * ```js
22015     * ['one','two']
22016     * ```
22017     *
22018     * which is vulnerable to attack, your server can return:
22019     * ```js
22020     * )]}',
22021     * ['one','two']
22022     * ```
22023     *
22024     * Angular will strip the prefix, before processing the JSON.
22025     *
22026     *
22027     * ### Cross Site Request Forgery (XSRF) Protection
22028     *
22029     * [XSRF](http://en.wikipedia.org/wiki/Cross-site_request_forgery) is an attack technique by
22030     * which the attacker can trick an authenticated user into unknowingly executing actions on your
22031     * website. Angular provides a mechanism to counter XSRF. When performing XHR requests, the
22032     * $http service reads a token from a cookie (by default, `XSRF-TOKEN`) and sets it as an HTTP
22033     * header (`X-XSRF-TOKEN`). Since only JavaScript that runs on your domain could read the
22034     * cookie, your server can be assured that the XHR came from JavaScript running on your domain.
22035     * The header will not be set for cross-domain requests.
22036     *
22037     * To take advantage of this, your server needs to set a token in a JavaScript readable session
22038     * cookie called `XSRF-TOKEN` on the first HTTP GET request. On subsequent XHR requests the
22039     * server can verify that the cookie matches `X-XSRF-TOKEN` HTTP header, and therefore be sure
22040     * that only JavaScript running on your domain could have sent the request. The token must be
22041     * unique for each user and must be verifiable by the server (to prevent the JavaScript from
22042     * making up its own tokens). We recommend that the token is a digest of your site's
22043     * authentication cookie with a [salt](https://en.wikipedia.org/wiki/Salt_(cryptography&#41;)
22044     * for added security.
22045     *
22046     * The name of the headers can be specified using the xsrfHeaderName and xsrfCookieName
22047     * properties of either $httpProvider.defaults at config-time, $http.defaults at run-time,
22048     * or the per-request config object.
22049     *
22050     * In order to prevent collisions in environments where multiple Angular apps share the
22051     * same domain or subdomain, we recommend that each application uses unique cookie name.
22052     *
22053     * @param {object} config Object describing the request to be made and how it should be
22054     *    processed. The object has following properties:
22055     *
22056     *    - **method** – `{string}` – HTTP method (e.g. 'GET', 'POST', etc)
22057     *    - **url** – `{string|TrustedObject}` – Absolute or relative URL of the resource that is being requested;
22058     *      or an object created by a call to `$sce.trustAsResourceUrl(url)`.
22059     *    - **params** – `{Object.<string|Object>}` – Map of strings or objects which will be serialized
22060     *      with the `paramSerializer` and appended as GET parameters.
22061     *    - **data** – `{string|Object}` – Data to be sent as the request message data.
22062     *    - **headers** – `{Object}` – Map of strings or functions which return strings representing
22063     *      HTTP headers to send to the server. If the return value of a function is null, the
22064     *      header will not be sent. Functions accept a config object as an argument.
22065     *    - **eventHandlers** - `{Object}` - Event listeners to be bound to the XMLHttpRequest object.
22066     *      To bind events to the XMLHttpRequest upload object, use `uploadEventHandlers`.
22067     *      The handler will be called in the context of a `$apply` block.
22068     *    - **uploadEventHandlers** - `{Object}` - Event listeners to be bound to the XMLHttpRequest upload
22069     *      object. To bind events to the XMLHttpRequest object, use `eventHandlers`.
22070     *      The handler will be called in the context of a `$apply` block.
22071     *    - **xsrfHeaderName** – `{string}` – Name of HTTP header to populate with the XSRF token.
22072     *    - **xsrfCookieName** – `{string}` – Name of cookie containing the XSRF token.
22073     *    - **transformRequest** –
22074     *      `{function(data, headersGetter)|Array.<function(data, headersGetter)>
22074}` –
22075     *      transform function or an array of such functions. The transform function takes the http
22076     *      request body and headers and returns its transformed (typically serialized) version.
22077     *      See {@link ng.$http#overriding-the-default-transformations-per-request
22078     *      Overriding the Default Transformations}
22079     *    - **transformResponse** –
22080     *      `{function(data, headersGetter, status)|Array.<function(data, headersGetter, status)>}` –
22081     *      transform function or an array of such functions. The transform function takes the http
22082     *      response body, headers and status and returns its transformed (typically deserialized) version.
22083     *      See {@link ng.$http#overriding-the-default-transformations-per-request
22084     *      Overriding the Default Transformations}
22085     *    - **paramSerializer** - `{string|function(Object<string,string>):string}` - A function used to
22086     *      prepare the string representation of request parameters (specified as an object).
22087     *      If specified as string, it is interpreted as function registered with the
22088     *      {@link $injector $injector}, which means you can create your own serializer
22089     *      by registering it as a {@link auto.$provide#service service}.
22090     *      The default serializer is the {@link $httpParamSerializer $httpParamSerializer};
22091     *      alternatively, you can use the {@link $httpParamSerializerJQLike $httpParamSerializerJQLike}
22092     *    - **cache** – `{boolean|Object}` – A boolean value or object created with
22093     *      {@link ng.$cacheFactory `$cacheFactory`} to enable or disable caching of the HTTP response.
22094     *      See {@link $http#caching $http Caching} for more information.
22095     *    - **timeout** – `{number|Promise}` – timeout in milliseconds, or {@link ng.$q promise}
22096     *      that should abort the request when resolved.
22097     *    - **withCredentials** - `{boolean}` - whether to set the `withCredentials` flag on the
22098     *      XHR object. See [requests with credentials](https://developer.mozilla.org/docs/Web/HTTP/Access_control_CORS#Requests_with_credentials)
22099     *      for more information.
22100     *    - **responseType** - `{string}` - see
22101     *      [XMLHttpRequest.responseType](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest#xmlhttprequest-responsetype).
22102     *
22103     * @returns {HttpPromise} Returns a {@link ng.$q `Promise}` that will be resolved to a response object
22104     *                        when the request succeeds or fails.
22105     *
22106     *
22107     * @property {Array.<Object>} pendingRequests Array of config objects for currently pending
22108     *   requests. This is primarily meant to be used for debugging purposes.
22109     *
22110     *
22111     * @example
22112<example module="httpExample" name="http-service">
22113<file name="index.html">
22114  <div ng-controller="FetchController">
22115    <select ng-model="method" aria-label="Request method">
22116      <option>GET</option>
22117      <option>JSONP</option>
22118    </select>
22119    <input type="text" ng-model="url" size="80" aria-label="URL" />
22120    <button id="fetchbtn" ng-click="fetch()">fetch</button><br>
22121    <button id="samplegetbtn" ng-click="updateModel('GET', 'http-hello.html')">Sample GET</button>
22122    <button id="samplejsonpbtn"
22123      ng-click="updateModel('JSONP',
22124                    'https://angularjs.org/greet.php?name=Super%20Hero')">
22125      Sample JSONP
22126    </button>
22127    <button id="invalidjsonpbtn"
22128      ng-click="updateModel('JSONP', 'https://angularjs.org/doesntexist')">
22129        Invalid JSONP
22130      </button>
22131    <pre>http status code: {{status}}</pre>
22132    <pre>http response data: {{data}}</pre>
22133  </div>
22134</file>
22135<file name="script.js">
22136  angular.module('httpExample', [])
22137    .config(['$sceDelegateProvider', function($sceDelegateProvider) {
22138      // We must whitelist the JSONP endpoint that we are using to show that we trust it
22139      $sceDelegateProvider.resourceUrlWhitelist([
22140        'self',
22141        'https://angularjs.org/**'
22142      ]);
22143    }])
22144    .controller('FetchController', ['$scope', '$http', '$templateCache',
22145      function($scope, $http, $templateCache) {
22146        $scope.method = 'GET';
22147        $scope.url = 'http-hello.html';
22148
22149        $scope.fetch = function() {
22150          $scope.code = null;
22151          $scope.response = null;
22152
22153          $http({method: $scope.method, url: $scope.url, cache: $templateCache}).
22154            then(function(response) {
22155              $scope.status = response.status;
22156              $scope.data = response.data;
22157            }, function(response) {
22158              $scope.data = response.data || 'Request failed';
22159              $scope.status = response.status;
22160          });
22161        };
22162
22163        $scope.updateModel = function(method, url) {
22164          $scope.method = method;
22165          $scope.url = url;
22166        };
22167      }]);
22168</file>
22169<file name="http-hello.html">
22170  Hello, $http!
22171</file>
22172<file name="protractor.js" type="protractor">
22173  var status = element(by.binding('status'));
22174  var data = element(by.binding('data'));
22175  var fetchBtn = element(by.id('fetchbtn'));
22176  var sampleGetBtn = element(by.id('samplegetbtn'));
22177  var invalidJsonpBtn = element(by.id('invalidjsonpbtn'));
22178
22179  it('should make an xhr GET request', function() {
22180    sampleGetBtn.click();
22181    fetchBtn.click();
22182    expect(status.getText()).toMatch('200');
22183    expect(data.getText()).toMatch(/Hello, \$http!/);
22184  });
22185
22186// Commented out due to flakes. See https://github.com/angular/angular.js/issues/9185
22187// it('should make a JSONP request to angularjs.org', function() {
22188//   var sampleJsonpBtn = element(by.id('samplejsonpbtn'));
22189//   sampleJsonpBtn.click();
22190//   fetchBtn.click();
22191//   expect(status.getText()).toMatch('200');
22192//   expect(data.getText()).toMatch(/Super Hero!/);
22193// });
22194
vendor: 4,111 bytes, lines 22195-22313
22195  it('should make JSONP request to invalid URL and invoke the error handler',
22196      function() {
22197    invalidJsonpBtn.click();
22198    fetchBtn.click();
22199    expect(status.getText()).toMatch('0');
22200    expect(data.getText()).toMatch('Request failed');
22201  });
22202</file>
22203</example>
22204     */
22205    function $http(requestConfig) {
22206
22207      if (!isObject(requestConfig)) {
22208        throw minErr('$http')('badreq', 'Http request configuration must be an object.  Received: {0}', requestConfig);
22209      }
22210
22211      if (!isString($sce.valueOf(requestConfig.url))) {
22212        throw minErr('$http')('badreq', 'Http request configuration url must be a string or a $sce trusted object.  Received: {0}', requestConfig.url);
22213      }
22214
22215      var config = extend({
22216        method: 'get',
22217        transformRequest: defaults.transformRequest,
22218        transformResponse: defaults.transformResponse,
22219        paramSerializer: defaults.paramSerializer,
22220        jsonpCallbackParam: defaults.jsonpCallbackParam
22221      }, requestConfig);
22222
22223      config.headers = mergeHeaders(requestConfig);
22224      config.method = uppercase(config.method);
22225      config.paramSerializer = isString(config.paramSerializer) ?
22226          $injector.get(config.paramSerializer) : config.paramSerializer;
22227
22228      $browser.$$incOutstandingRequestCount();
22229
22230      var requestInterceptors = [];
22231      var responseInterceptors = [];
22232      var promise = $q.resolve(config);
22233
22234      // apply interceptors
22235      forEach(reversedInterceptors, function(interceptor) {
22236        if (interceptor.request || interceptor.requestError) {
22237          requestInterceptors.unshift(interceptor.request, interceptor.requestError);
22238        }
22239        if (interceptor.response || interceptor.responseError) {
22240          responseInterceptors.push(interceptor.response, interceptor.responseError);
22241        }
22242      });
22243
22244      promise = chainInterceptors(promise, requestInterceptors);
22245      promise = promise.then(serverRequest);
22246      promise = chainInterceptors(promise, responseInterceptors);
22247      promise = promise.finally(completeOutstandingRequest);
22248
22249      return promise;
22250
22251
22252      function chainInterceptors(promise, interceptors) {
22253        for (var i = 0, ii = interceptors.length; i < ii;) {
22254          var thenFn = interceptors[i++];
22255          var rejectFn = interceptors[i++];
22256
22257          promise = promise.then(thenFn, rejectFn);
22258        }
22259
22260        interceptors.length = 0;
22261
22262        return promise;
22263      }
22264
22265      function completeOutstandingRequest() {
22266        $browser.$$completeOutstandingRequest(noop);
22267      }
22268
22269      function executeHeaderFns(headers, config) {
22270        var headerContent, processedHeaders = {};
22271
22272        forEach(headers, function(headerFn, header) {
22273          if (isFunction(headerFn)) {
22274            headerContent = headerFn(config);
22275            if (headerContent != null) {
22276              processedHeaders[header] = headerContent;
22277            }
22278          } else {
22279            processedHeaders[header] = headerFn;
22280          }
22281        });
22282
22283        return processedHeaders;
22284      }
22285
22286      function mergeHeaders(config) {
22287        var defHeaders = defaults.headers,
22288            reqHeaders = extend({}, config.headers),
22289            defHeaderName, lowercaseDefHeaderName, reqHeaderName;
22290
22291        defHeaders = extend({}, defHeaders.common, defHeaders[lowercase(config.method)]);
22292
22293        // using for-in instead of forEach to avoid unnecessary iteration after header has been found
22294        defaultHeadersIteration:
22295        for (defHeaderName in defHeaders) {
22296          lowercaseDefHeaderName = lowercase(defHeaderName);
22297
22298          for (reqHeaderName in reqHeaders) {
22299            if (lowercase(reqHeaderName) === lowercaseDefHeaderName) {
22300              continue defaultHeadersIteration;
22301            }
22302          }
22303
22304          reqHeaders[defHeaderName] = defHeaders[defHeaderName];
22305        }
22306
22307        // execute if header value is a function for merged headers
22308        return executeHeaderFns(reqHeaders, shallowCopy(config));
22309      }
22310
22311      function serverRequest(config) {
22312        var headers = config.headers;
22313        var reqData = transformData(config.data, headersGetter(headers), undefined, c
vendor: 20,279 bytes, lines 22313-22918
22313onfig.transformRequest);
22314
22315        // strip content-type if data is undefined
22316        if (isUndefined(reqData)) {
22317          forEach(headers, function(value, header) {
22318            if (lowercase(header) === 'content-type') {
22319              delete headers[header];
22320            }
22321          });
22322        }
22323
22324        if (isUndefined(config.withCredentials) && !isUndefined(defaults.withCredentials)) {
22325          config.withCredentials = defaults.withCredentials;
22326        }
22327
22328        // send request
22329        return sendReq(config, reqData).then(transformResponse, transformResponse);
22330      }
22331
22332      function transformResponse(response) {
22333        // make a copy since the response must be cacheable
22334        var resp = extend({}, response);
22335        resp.data = transformData(response.data, response.headers, response.status,
22336                                  config.transformResponse);
22337        return (isSuccess(response.status))
22338          ? resp
22339          : $q.reject(resp);
22340      }
22341    }
22342
22343    $http.pendingRequests = [];
22344
22345    /**
22346     * @ngdoc method
22347     * @name $http#get
22348     *
22349     * @description
22350     * Shortcut method to perform `GET` request.
22351     *
22352     * @param {string|TrustedObject} url Absolute or relative URL of the resource that is being requested;
22353     *                                   or an object created by a call to `$sce.trustAsResourceUrl(url)`.
22354     * @param {Object=} config Optional configuration object
22355     * @returns {HttpPromise} Future object
22356     */
22357
22358    /**
22359     * @ngdoc method
22360     * @name $http#delete
22361     *
22362     * @description
22363     * Shortcut method to perform `DELETE` request.
22364     *
22365     * @param {string|TrustedObject} url Absolute or relative URL of the resource that is being requested;
22366     *                                   or an object created by a call to `$sce.trustAsResourceUrl(url)`.
22367     * @param {Object=} config Optional configuration object
22368     * @returns {HttpPromise} Future object
22369     */
22370
22371    /**
22372     * @ngdoc method
22373     * @name $http#head
22374     *
22375     * @description
22376     * Shortcut method to perform `HEAD` request.
22377     *
22378     * @param {string|TrustedObject} url Absolute or relative URL of the resource that is being requested;
22379     *                                   or an object created by a call to `$sce.trustAsResourceUrl(url)`.
22380     * @param {Object=} config Optional configuration object
22381     * @returns {HttpPromise} Future object
22382     */
22383
22384    /**
22385     * @ngdoc method
22386     * @name $http#jsonp
22387     *
22388     * @description
22389     * Shortcut method to perform `JSONP` request.
22390     *
22391     * Note that, since JSONP requests are sensitive because the response is given full access to the browser,
22392     * the url must be declared, via {@link $sce} as a trusted resource URL.
22393     * You can trust a URL by adding it to the whitelist via
22394     * {@link $sceDelegateProvider#resourceUrlWhitelist  `$sceDelegateProvider.resourceUrlWhitelist`} or
22395     * by explicitly trusting the URL via {@link $sce#trustAsResourceUrl `$sce.trustAsResourceUrl(url)`}.
22396     *
22397     * JSONP requests must specify a callback to be used in the response from the server. This callback
22398     * is passed as a query parameter in the request. You must specify the name of this parameter by
22399     * setting the `jsonpCallbackParam` property on the request config object.
22400     *
22401     * ```
22402     * $http.jsonp('some/trusted/url', {jsonpCallbackParam: 'callback'})
22403     * ```
22404     *
22405     * You can also specify a default callback parameter name in `$http.defaults.jsonpCallbackParam`.
22406     * Initially this is set to `'callback'`.
22407     *
22408     * <div class="alert alert-danger">
22409     * You can no longer use the `JSON_CALLBACK` string as a placeholder for specifying where the callback
22410     * parameter value should go.
22411     * </div>
22412     *
22413     * If you would like to customise where and how the callbacks are stored then try overriding
22414     * or decorating the {@link $jsonpCallbacks} service.
22415     *
22416     * @param {string|TrustedObject} url Absolute or relative URL of the resource that is being requested;
22417     *                                   or an object created by a call to `$sce.trustAsResourceUrl(url)`.
22418     * @param {Object=} config Optional configuration object
22419     * @returns {HttpPromise} Future object
22420     */
22421    createShortMethods('get', 'delete', 'head', 'jsonp');
22422
22423    /**
22424     * @ngdoc method
22425     * @name $http#post
22426     *
22427     * @description
22428     * Shortcut method to perform `POST` request.
22429     *
22430     * @param {string} url Relative or absolute URL specifying the destination of the request
22431     * @param {*} data Request content
22432     * @param {Object=} config Optional configuration object
22433     * @returns {HttpPromise} Future object
22434     */
22435
22436    /**
22437     * @ngdoc method
22438     * @name $http#put
22439     *
22440     * @description
22441     * Shortcut method to perform `PUT` request.
22442     *
22443     * @param {string} url Relative or absolute URL specifying the destination of the request
22444     * @param {*} data Request content
22445     * @param {Object=} config Optional configuration object
22446     * @returns {HttpPromise} Future object
22447     */
22448
22449     /**
22450      * @ngdoc method
22451      * @name $http#patch
22452      *
22453      * @description
22454      * Shortcut method to perform `PATCH` request.
22455      *
22456      * @param {string} url Relative or absolute URL specifying the destination of the request
22457      * @param {*} data Request content
22458      * @param {Object=} config Optional configuration object
22459      * @returns {HttpPromise} Future object
22460      */
22461    createShortMethodsWithData('post', 'put', 'patch');
22462
22463        /**
22464         * @ngdoc property
22465         * @name $http#defaults
22466         *
22467         * @description
22468         * Runtime equivalent of the `$httpProvider.defaults` property. Allows configuration of
22469         * default headers, withCredentials as well as request and response transformations.
22470         *
22471         * See "Setting HTTP Headers" and "Transforming Requests and Responses" sections above.
22472         */
22473    $http.defaults = defaults;
22474
22475
22476    return $http;
22477
22478
22479    function createShortMethods(names) {
22480      forEach(arguments, function(name) {
22481        $http[name] = function(url, config) {
22482          return $http(extend({}, config || {}, {
22483            method: name,
22484            url: url
22485          }));
22486        };
22487      });
22488    }
22489
22490
22491    function createShortMethodsWithData(name) {
22492      forEach(arguments, function(name) {
22493        $http[name] = function(url, data, config) {
22494          return $http(extend({}, config || {}, {
22495            method: name,
22496            url: url,
22497            data: data
22498          }));
22499        };
22500      });
22501    }
22502
22503
22504    /**
22505     * Makes the request.
22506     *
22507     * !!! ACCESSES CLOSURE VARS:
22508     * $httpBackend, defaults, $log, $rootScope, defaultCache, $http.pendingRequests
22509     */
22510    function sendReq(config, reqData) {
22511      var deferred = $q.defer(),
22512          promise = deferred.promise,
22513          cache,
22514          cachedResp,
22515          reqHeaders = config.headers,
22516          isJsonp = lowercase(config.method) === 'jsonp',
22517          url = config.url;
22518
22519      if (isJsonp) {
22520        // JSONP is a pretty sensitive operation where we're allowing a script to have full access to
22521        // our DOM and JS space.  So we require that the URL satisfies SCE.RESOURCE_URL.
22522        url = $sce.getTrustedResourceUrl(url);
22523      } else if (!isString(url)) {
22524        // If it is not a string then the URL must be a $sce trusted object
22525        url = $sce.valueOf(url);
22526      }
22527
22528      url = buildUrl(url, config.paramSerializer(config.params));
22529
22530      if (isJsonp) {
22531        // Check the url and add the JSONP callback placeholder
22532        url = sanitizeJsonpCallbackParam(url, config.jsonpCallbackParam);
22533      }
22534
22535      $http.pendingRequests.push(config);
22536      promise.then(removePendingReq, removePendingReq);
22537
22538      if ((config.cache || defaults.cache) && config.cache !== false &&
22539          (config.method === 'GET' || config.method === 'JSONP')) {
22540        cache = isObject(config.cache) ? config.cache
22541            : isObject(/** @type {?} */ (defaults).cache)
22542              ? /** @type {?} */ (defaults).cache
22543              : defaultCache;
22544      }
22545
22546      if (cache) {
22547        cachedResp = cache.get(url);
22548        if (isDefined(cachedResp)) {
22549          if (isPromiseLike(cachedResp)) {
22550            // cached request has already been sent, but there is no response yet
22551            cachedResp.then(resolvePromiseWithResult, resolvePromiseWithResult);
22552          } else {
22553            // serving from cache
22554            if (isArray(cachedResp)) {
22555              resolvePromise(cachedResp[1], cachedResp[0], shallowCopy(cachedResp[2]), cachedResp[3]);
22556            } else {
22557              resolvePromise(cachedResp, 200, {}, 'OK');
22558            }
22559          }
22560        } else {
22561          // put the promise for the non-transformed response into cache as a placeholder
22562          cache.put(url, promise);
22563        }
22564      }
22565
22566
22567      // if we won't have the response in cache, set the xsrf headers and
22568      // send the request to the backend
22569      if (isUndefined(cachedResp)) {
22570        var xsrfValue = urlIsSameOrigin(config.url)
22571            ? $$cookieReader()[config.xsrfCookieName || defaults.xsrfCookieName]
22572            : undefined;
22573        if (xsrfValue) {
22574          reqHeaders[(config.xsrfHeaderName || defaults.xsrfHeaderName)] = xsrfValue;
22575        }
22576
22577        $httpBackend(config.method, url, reqData, done, reqHeaders, config.timeout,
22578            config.withCredentials, config.responseType,
22579            createApplyHandlers(config.eventHandlers),
22580            createApplyHandlers(config.uploadEventHandlers));
22581      }
22582
22583      return promise;
22584
22585      function createApplyHandlers(eventHandlers) {
22586        if (eventHandlers) {
22587          var applyHandlers = {};
22588          forEach(eventHandlers, function(eventHandler, key) {
22589            applyHandlers[key] = function(event) {
22590              if (useApplyAsync) {
22591                $rootScope.$applyAsync(callEventHandler);
22592              } else if ($rootScope.$$phase) {
22593                callEventHandler();
22594              } else {
22595                $rootScope.$apply(callEventHandler);
22596              }
22597
22598              function callEventHandler() {
22599                eventHandler(event);
22600              }
22601            };
22602          });
22603          return applyHandlers;
22604        }
22605      }
22606
22607
22608      /**
22609       * Callback registered to $httpBackend():
22610       *  - caches the response if desired
22611       *  - resolves the raw $http promise
22612       *  - calls $apply
22613       */
22614      function done(status, response, headersString, statusText) {
22615        if (cache) {
22616          if (isSuccess(status)) {
22617            cache.put(url, [status, response, parseHeaders(headersString), statusText]);
22618          } else {
22619            // remove promise from the cache
22620            cache.remove(url);
22621          }
22622        }
22623
22624        function resolveHttpPromise() {
22625          resolvePromise(response, status, headersString, statusText);
22626        }
22627
22628        if (useApplyAsync) {
22629          $rootScope.$applyAsync(resolveHttpPromise);
22630        } else {
22631          resolveHttpPromise();
22632          if (!$rootScope.$$phase) $rootScope.$apply();
22633        }
22634      }
22635
22636
22637      /**
22638       * Resolves the raw $http promise.
22639       */
22640      function resolvePromise(response, status, headers, statusText) {
22641        //status: HTTP response status code, 0, -1 (aborted by timeout / promise)
22642        status = status >= -1 ? status : 0;
22643
22644        (isSuccess(status) ? deferred.resolve : deferred.reject)({
22645          data: response,
22646          status: status,
22647          headers: headersGetter(headers),
22648          config: config,
22649          statusText: statusText
22650        });
22651      }
22652
22653      function resolvePromiseWithResult(result) {
22654        resolvePromise(result.data, result.status, shallowCopy(result.headers()), result.statusText);
22655      }
22656
22657      function removePendingReq() {
22658        var idx = $http.pendingRequests.indexOf(config);
22659        if (idx !== -1) $http.pendingRequests.splice(idx, 1);
22660      }
22661    }
22662
22663
22664    function buildUrl(url, serializedParams) {
22665      if (serializedParams.length > 0) {
22666        url += ((url.indexOf('?') === -1) ? '?' : '&') + serializedParams;
22667      }
22668      return url;
22669    }
22670
22671    function sanitizeJsonpCallbackParam(url, key) {
22672      if (/[&?][^=]+=JSON_CALLBACK/.test(url)) {
22673        // Throw if the url already contains a reference to JSON_CALLBACK
22674        throw $httpMinErr('badjsonp', 'Illegal use of JSON_CALLBACK in url, "{0}"', url);
22675      }
22676
22677      var callbackParamRegex = new RegExp('[&?]' + key + '=');
22678      if (callbackParamRegex.test(url)) {
22679        // Throw if the callback param was already provided
22680        throw $httpMinErr('badjsonp', 'Illegal use of callback param, "{0}", in url, "{1}"', key, url);
22681      }
22682
22683      // Add in the JSON_CALLBACK callback param value
22684      url += ((url.indexOf('?') === -1) ? '?' : '&') + key + '=JSON_CALLBACK';
22685
22686      return url;
22687    }
22688  }];
22689}
22690
22691/**
22692 * @ngdoc service
22693 * @name $xhrFactory
22694 * @this
22695 *
22696 * @description
22697 * Factory function used to create XMLHttpRequest objects.
22698 *
22699 * Replace or decorate this service to create your own custom XMLHttpRequest objects.
22700 *
22701 * ```
22702 * angular.module('myApp', [])
22703 * .factory('$xhrFactory', function() {
22704 *   return function createXhr(method, url) {
22705 *     return new window.XMLHttpRequest({mozSystem: true});
22706 *   };
22707 * });
22708 * ```
22709 *
22710 * @param {string} method HTTP method of the request (GET, POST, PUT, ..)
22711 * @param {string} url URL of the request.
22712 */
22713function $xhrFactoryProvider() {
22714  this.$get = function() {
22715    return function createXhr() {
22716      return new window.XMLHttpRequest();
22717    };
22718  };
22719}
22720
22721/**
22722 * @ngdoc service
22723 * @name $httpBackend
22724 * @requires $jsonpCallbacks
22725 * @requires $document
22726 * @requires $xhrFactory
22727 * @this
22728 *
22729 * @description
22730 * HTTP backend used by the {@link ng.$http service} that delegates to
22731 * XMLHttpRequest object or JSONP and deals with browser incompatibilities.
22732 *
22733 * You should never need to use this service directly, instead use the higher-level abstractions:
22734 * {@link ng.$http $http} or {@link ngResource.$resource $resource}.
22735 *
22736 * During testing this implementation is swapped with {@link ngMock.$httpBackend mock
22737 * $httpBackend} which can be trained with responses.
22738 */
22739function $HttpBackendProvider() {
22740  this.$get = ['$browser', '$jsonpCallbacks', '$document', '$xhrFactory', function($browser, $jsonpCallbacks, $document, $xhrFactory) {
22741    return createHttpBackend($browser, $xhrFactory, $browser.defer, $jsonpCallbacks, $document[0]);
22742  }];
22743}
22744
22745function createHttpBackend($browser, createXhr, $browserDefer, callbacks, rawDocument) {
22746  // TODO(vojta): fix the signature
22747  return function(method, url, post, callback, headers, timeout, withCredentials, responseType, eventHandlers, uploadEventHandlers) {
22748    url = url || $browser.url();
22749
22750    if (lowercase(method) === 'jsonp') {
22751      var callbackPath = callbacks.createCallback(url);
22752      var jsonpDone = jsonpReq(url, callbackPath, function(status, text) {
22753        // jsonpReq only ever sets status to 200 (OK), 404 (ERROR) or -1 (WAITING)
22754        var response = (status === 200) && callbacks.getResponse(callbackPath);
22755        completeRequest(callback, status, response, '', text);
22756        callbacks.removeCallback(callbackPath);
22757      });
22758    } else {
22759
22760      var xhr = createXhr(method, url);
22761
22762      xhr.open(method, url, true);
22763      forEach(headers, function(value, key) {
22764        if (isDefined(value)) {
22765            xhr.setRequestHeader(key, value);
22766        }
22767      });
22768
22769      xhr.onload = function requestLoaded() {
22770        var statusText = xhr.statusText || '';
22771
22772        // responseText is the old-school way of retrieving response (supported by IE9)
22773        // response/responseType properties were introduced in XHR Level2 spec (supported by IE10)
22774        var response = ('response' in xhr) ? xhr.response : xhr.responseText;
22775
22776        // normalize IE9 bug (http://bugs.jquery.com/ticket/1450)
22777        var status = xhr.status === 1223 ? 204 : xhr.status;
22778
22779        // fix status code when it is 0 (0 status is undocumented).
22780        // Occurs when accessing file resources or on Android 4.1 stock browser
22781        // while retrieving files from application cache.
22782        if (status === 0) {
22783          status = response ? 200 : urlResolve(url).protocol === 'file' ? 404 : 0;
22784        }
22785
22786        completeRequest(callback,
22787            status,
22788            response,
22789            xhr.getAllResponseHeaders(),
22790            statusText);
22791      };
22792
22793      var requestError = function() {
22794        // The response is always empty
22795        // See https://xhr.spec.whatwg.org/#request-error-steps and https://fetch.spec.whatwg.org/#concept-network-error
22796        completeRequest(callback, -1, null, null, '');
22797      };
22798
22799      xhr.onerror = requestError;
22800      xhr.onabort = requestError;
22801      xhr.ontimeout = requestError;
22802
22803      forEach(eventHandlers, function(value, key) {
22804          xhr.addEventListener(key, value);
22805      });
22806
22807      forEach(uploadEventHandlers, function(value, key) {
22808        xhr.upload.addEventListener(key, value);
22809      });
22810
22811      if (withCredentials) {
22812        xhr.withCredentials = true;
22813      }
22814
22815      if (responseType) {
22816        try {
22817          xhr.responseType = responseType;
22818        } catch (e) {
22819          // WebKit added support for the json responseType value on 09/03/2013
22820          // https://bugs.webkit.org/show_bug.cgi?id=73648. Versions of Safari prior to 7 are
22821          // known to throw when setting the value "json" as the response type. Other older
22822          // browsers implementing the responseType
22823          //
22824          // The json response type can be ignored if not supported, because JSON payloads are
22825          // parsed on the client-side regardless.
22826          if (responseType !== 'json') {
22827            throw e;
22828          }
22829        }
22830      }
22831
22832      xhr.send(isUndefined(post) ? null : post);
22833    }
22834
22835    if (timeout > 0) {
22836      var timeoutId = $browserDefer(timeoutRequest, timeout);
22837    } else if (isPromiseLike(timeout)) {
22838      timeout.then(timeoutRequest);
22839    }
22840
22841
22842    function timeoutRequest() {
22843      if (jsonpDone) {
22844        jsonpDone();
22845      }
22846      if (xhr) {
22847        xhr.abort();
22848      }
22849    }
22850
22851    function completeRequest(callback, status, response, headersString, statusText) {
22852      // cancel timeout and subsequent timeout promise resolution
22853      if (isDefined(timeoutId)) {
22854        $browserDefer.cancel(timeoutId);
22855      }
22856      jsonpDone = xhr = null;
22857
22858      callback(status, response, headersString, statusText);
22859    }
22860  };
22861
22862  function jsonpReq(url, callbackPath, done) {
22863    url = url.replace('JSON_CALLBACK', callbackPath);
22864    // we can't use jQuery/jqLite here because jQuery does crazy stuff with script elements, e.g.:
22865    // - fetches local scripts via XHR and evals them
22866    // - adds and immediately removes script elements from the document
22867    var script = rawDocument.createElement('script'), callback = null;
22868    script.type = 'text/javascript';
22869    script.src = url;
22870    script.async = true;
22871
22872    callback = function(event) {
22873      script.removeEventListener('load', callback);
22874      script.removeEventListener('error', callback);
22875      rawDocument.body.removeChild(script);
22876      script = null;
22877      var status = -1;
22878      var text = 'unknown';
22879
22880      if (event) {
22881        if (event.type === 'load' && !callbacks.wasCalled(callbackPath)) {
22882          event = { type: 'error' };
22883        }
22884        text = event.type;
22885        status = event.type === 'error' ? 404 : 200;
22886      }
22887
22888      if (done) {
22889        done(status, text);
22890      }
22891    };
22892
22893    script.addEventListener('load', callback);
22894    script.addEventListener('error', callback);
22895    rawDocument.body.appendChild(script);
22896    return callback;
22897  }
22898}
22899
22900var $interpolateMinErr = angular.$interpolateMinErr = minErr('$interpolate');
22901$interpolateMinErr.throwNoconcat = function(text) {
22902  throw $interpolateMinErr('noconcat',
22903      'Error while interpolating: {0}\nStrict Contextual Escaping disallows ' +
22904      'interpolations that concatenate multiple expressions when a trusted value is ' +
22905      'required.  See http://docs.angularjs.org/api/ng.$sce', text);
22906};
22907
22908$interpolateMinErr.interr = function(text, err) {
22909  return $interpolateMinErr('interr', 'Can\'t interpolate: {0}\n{1}', text, err.toString());
22910};
22911
22912/**
22913 * @ngdoc provider
22914 * @name $interpolateProvider
22915 * @this
22916 *
22917 * @description
22918 *
22919 * Used for configuring the interpolation markup. Defaults to `{{` and `}}`.
22920 *
22921 * <div class="alert alert-danger">
22922 * This feature is sometimes used to mix different markup languages, e.g. to wrap an Angular
22923 * template within a Python Jinja template (or any other template language). Mixing templating
22924 * languages is **very dangerous**. The embedding template language will not safely escape Angular
22925 * expressions, so any user-controlled values in the template will cause Cross Site Scripting (XSS)
22926 * security bugs!
22927 * </div>
22928 *
22929 * @example
22930<example name="custom-interpolation-markup" module="customInterpolationApp">
22931<file name="index.html">
22932<script>
22933  var customInterpolationApp = angular.module('customInterpolationApp', []);
22934
22935  customInterpolationApp.config(function($interpolateProvider) {
22936    $interpolateProvider.startSymbol('//');
22937    $interpolateProvider.endSymbol('//');
22938  });
22939
22940
22941  customInterpolationApp.controller('DemoController', function() {
22942      this.label = "This binding is brought you by // interpolation symbols.";
22943  });
22944</script>
22945<div ng-controller="DemoController as demo">
22946    //demo.label//
22947</div>
22948</file>
22949<file name="protractor.js" type="protractor">
22950  it('should interpolate binding with custom symbols', function() {
22951    expect(element(by.binding('demo.label')).getText()).toBe('This binding is brought you by // interpolation symbols.');
22952  });
22953</file>
22954</example>
22955 */
22956function $InterpolateProvider() {
22957  var startSymbol = '{{';
22958  var endSymbol = '}}';
22959
22960  /**
22961   * @ngdoc method
22962   * @name $interpolateProvider#startSymbol
22963   * @description
22964   * Symbol to denote start of expression in the interpolated string. Defaults to `{{`.
22965   *
22966   * @param {string=} value new value to set the starting symbol to.
22967   * @returns {string|self} Returns the symbol when used as getter and self if used as setter.
22968   */
22969  this.startSymbol = function(value) {
22970    if (value) {
22971      startSymbol = value;
22972      return this;
22973    } else {
22974      return startSymbol;
22975    }
22976  };
22977
22978  /**
22979   * @ngdoc method
22980   * @name $interpolateProvider#endSymbol
22981   * @description
22982   * Symbol to denote the end of expression in the interpolated string. Defaults to `}}`.
22983   *
22984   * @param {string=} value new value to set the ending symbol to.
22985   * @returns {string|self} Returns the symbol when used as getter and self if used as setter.
22986   */
22987  this.endSymbol = function(value) {
22988    if (value) {
22989      endSymbol = value;
22990      return this;
22991    } else {
22992      return endSymbol;
22993    }
22994  };
22995
22996
22997  this.$get = ['$parse', '$exceptionHandler', '$sce', function($parse, $exceptionHandler, $sce) {
22998    var startSymbolLength = startSymbol.length,
22999        endSymbolLength = endSymbol.length,
23000        escapedStartRegexp = new RegExp(startSymbol.replace(/./g, escape), 'g'),
23001        escapedEndRegexp = new RegExp(endSymbol.replace(/./g, escape), 'g');
23002
23003    function escape(ch) {
23004      return '\\\\\\' + ch;
23005    }
23006
23007    function unescapeText(text) {
23008      return text.replace(escapedStartRegexp, startSymbol).
23009        replace(escapedEndRegexp, endSymbol);
23010    }
23011
23012    // TODO: this is the same as the constantWatchDelegate in parse.js
23013    function constantWatchDelegate(scope, listener, objectEquality, constantInterp) {
23014      var unwatch = scope.$watch(function constantInterpolateWatch(scope) {
23015        unwatch();
23016        return constantInterp(scope);
23017      }, listener, objectEquality);
23018      return unwatch;
23019    }
23020
23021    /**
23022     * @ngdoc service
23023     * @name $interpolate
23024     * @kind function
23025     *
23026     * @requires $parse
23027     * @requires $sce
23028     *
23029     * @description
23030     *
23031     * Compiles a string with markup into an interpolation function. This service is used by the
23032     * HTML {@link ng.$compile $compile} service for data binding. See
23033     * {@link ng.$interpolateProvider $interpolateProvider} for configuring the
23034     * interpolation markup.
23035     *
23036     *
23037     * ```js
23038     *   var $interpolate = ...; // injected
23039     *   var exp = $interpolate('Hello {{name | uppercase}}!');
23040     *   expect(exp({name:'Angular'})).toEqual('Hello ANGULAR!');
23041     * ```
23042     *
23043     * `$interpolate` takes an optional fourth argument, `allOrNothing`. If `allOrNothing` is
23044     * `true`, the interpolation function will return `undefined` unless all embedded expressions
23045     * evaluate to a value other than `undefined`.
23046     *
23047     * ```js
23048     *   var $interpolate = ...; // injected
23049     *   var context = {greeting: 'Hello', name: undefined };
23050     *
23051     *   // default "forgiving" mode
23052     *   var exp = $interpolate('{{greeting}} {{name}}!');
23053     *   expect(exp(context)).toEqual('Hello !');
23054     *
23055     *   // "allOrNothing" mode
23056     *   exp = $interpolate('{{greeting}} {{name}}!', false, null, true);
23057     *   expect(exp(context)).toBeUndefined();
23058     *   context.name = 'Angular';
23059     *   expect(exp(context)).toEqual('Hello Angular!');
23060     * ```
23061     *
23062     * `allOrNothing` is useful for interpolating URLs. `ngSrc` and `ngSrcset` use this behavior.
23063     *
23064     * #### Escaped Interpolation
23065     * $interpolate provides a mechanism for escaping interpolation markers. Start and end markers
23066     * can be escaped by preceding each of their characters with a REVERSE SOLIDUS U+005C (backslash).
23067     * It will be rendered as a regular start/end marker, and will not be interpreted as an expression
23068     * or binding.
23069     *
23070     * This enables web-servers to prevent script injection attacks and defacing attacks, to some
23071     * degree, while also enabling code examples to work without relying on the
23072     * {@link ng.directive:ngNonBindable ngNonBindable} directive.
23073     *
23074     * **For security purposes, it is strongly encouraged that web servers escape user-supplied data,
23075     * replacing angle brackets (&lt;, &gt;) with &amp;lt; and &amp;gt; respectively, and replacing all
23076     * interpolation start/end markers with their escaped counterparts.**
23077     *
23078     * Escaped interpolation markers are only replaced with the actual interpolation markers in rendered
23079     * output when the $interpolate service processes the text. So, for HTML elements interpolated
23080     * by {@link ng.$compile $compile}
23080, or otherwise interpolated with the `mustHaveExpression` parameter
23081     * set to `true`, the interpolated text must contain an unescaped interpolation expression. As such,
23082     * this is typically useful only when user-data is used in rendering a template from the server, or
23083     * when otherwise untrusted data is used by a directive.
23084     *
23085     * <example name="interpolation">
23086     *  <file name="index.html">
23087     *    <div ng-init="username='A user'">
23088     *      <p ng-init="apptitle='Escaping demo'">{{apptitle}}: \{\{ username = "defaced value"; \}\}
23089     *        </p>
23090     *      <p><strong>{{username}}</strong> attempts to inject code which will deface the
23091     *        application, but fails to accomplish their task, because the server has correctly
23092     *        escaped the interpolation start/end markers with REVERSE SOLIDUS U+005C (backslash)
23093     *        characters.</p>
23094     *      <p>Instead, the result of the attempted script injection is visible, and can be removed
23095     *        from the database by an administrator.</p>
23096     *    </div>
23097     *  </file>
23098     * </example>
23099     *
23100     * @knownIssue
23101     * It is currently not possible for an interpolated expression to contain the interpolation end
23102     * symbol. For example, `{{ '}}' }}` will be incorrectly interpreted as `{{ ' }}` + `' }}`, i.e.
23103     * an interpolated expression consisting of a single-quote (`'`) and the `' }}` string.
23104     *
23105     * @knownIssue
23106     * All directives and components must use the standard `{{` `}}` interpolation symbols
23107     * in their templates. If you change the application interpolation symbols the {@link $compile}
23108     * service will attempt to denormalize the standard symbols to the custom symbols.
23109     * The denormalization process is not clever enough to know not to replace instances of the standard
23110     * symbols where they would not normally be treated as interpolation symbols. For example in the following
23111     * code snippet the closing braces of the literal object will get incorrectly denormalized:
23112     *
23113     * ```
23114     * <div data-context='{"context":{"id":3,"type":"page"}}">
23115     * ```
23116     *
23117     * The workaround is to ensure that such instances are separated by whitespace:
23118     * ```
23119     * <div data-context='{"context":{"id":3,"type":"page"} }">
23120     * ```
23121     *
23122     * See https://github.com/angular/angular.js/pull/14610#issuecomment-219401099 for more information.
23123     *
23124     * @param {string} text The text with markup to interpolate.
23125     * @param {boolean=} mustHaveExpression if set to true then the interpolation string must have
23126     *    embedded expression in order to return an interpolation function. Strings with no
23127     *    embedded expression will return null for the interpolation function.
23128     * @param {string=} trustedContext when provided, the returned function passes the interpolated
23129     *    result through {@link ng.$sce#getTrusted $sce.getTrusted(interpolatedResult,
23130     *    trustedContext)} before returning it.  Refer to the {@link ng.$sce $sce} service that
23131     *    provides Strict Contextual Escaping for details.
23132     * @param {boolean=} allOrNothing if `true`, then the returned function returns undefined
23133     *    unless all embedded expressions evaluate to a value other than `undefined`.
23134     * @returns {function(context)} an interpolation function which is used to compute the
23135     *    interpolated string. The function has these parameters:
23136     *
23137     * - `context`: evaluation context for all expressions embedded in the interpolated text
23138     */
23139    function $interpolate(text, mustHaveExpression, trustedContext, allOrNothing) {
23140      // Provide a quick exit and simplified result function for text with no interpolation
23141      if (!text.length || text.indexOf(startSymbol) === -1) {
23142        var constantInterp;
23143        if (!mustHaveExpression) {
23144          var unescapedText = unescapeText(text);
23145          constantInterp = valueFn(unescapedText);
23146          constantInterp.exp = text;
23147          constantInterp.expressions = [];
23148          constantInterp.$$watchDelegate = constantWatchDelegate;
23149        }
23150        return constantInterp;
23151      }
23152
23153      allOrNothing = !!allOrNothing;
23154      var startIndex,
23155          endIndex,
23156          index = 0,
23157          expressions = [],
23158          parseFns = [],
23159          textLength = text.length,
23160          exp,
23161          concat = [],
23162          expressionPositions = [];
23163
23164      while (index < textLength) {
23165        if (((startIndex = text.indexOf(startSymbol, index)) !== -1) &&
23166             ((endIndex = text.indexOf(endSymbol, startIndex + startSymbolLength)) !== -1)) {
23167          if (index !== startIndex) {
23168            concat.push(unescapeText(text.substring(index, startIndex)));
23169          }
23170          exp = text.substring(startIndex + startSymbolLength, endIndex);
23171          expressions.push(exp);
23172          parseFns.push($parse(exp, parseStringifyInterceptor));
vendor: 4,127 bytes, lines 23173-23298
23173          index = endIndex + endSymbolLength;
23174          expressionPositions.push(concat.length);
23175          concat.push('');
23176        } else {
23177          // we did not find an interpolation, so we have to add the remainder to the separators array
23178          if (index !== textLength) {
23179            concat.push(unescapeText(text.substring(index)));
23180          }
23181          break;
23182        }
23183      }
23184
23185      // Concatenating expressions makes it hard to reason about whether some combination of
23186      // concatenated values are unsafe to use and could easily lead to XSS.  By requiring that a
23187      // single expression be used for iframe[src], object[src], etc., we ensure that the value
23188      // that's used is assigned or constructed by some JS code somewhere that is more testable or
23189      // make it obvious that you bound the value to some user controlled value.  This helps reduce
23190      // the load when auditing for XSS issues.
23191      if (trustedContext && concat.length > 1) {
23192          $interpolateMinErr.throwNoconcat(text);
23193      }
23194
23195      if (!mustHaveExpression || expressions.length) {
23196        var compute = function(values) {
23197          for (var i = 0, ii = expressions.length; i < ii; i++) {
23198            if (allOrNothing && isUndefined(values[i])) return;
23199            concat[expressionPositions[i]] = values[i];
23200          }
23201          return concat.join('');
23202        };
23203
23204        var getValue = function(value) {
23205          return trustedContext ?
23206            $sce.getTrusted(trustedContext, value) :
23207            $sce.valueOf(value);
23208        };
23209
23210        return extend(function interpolationFn(context) {
23211            var i = 0;
23212            var ii = expressions.length;
23213            var values = new Array(ii);
23214
23215            try {
23216              for (; i < ii; i++) {
23217                values[i] = parseFns[i](context);
23218              }
23219
23220              return compute(values);
23221            } catch (err) {
23222              $exceptionHandler($interpolateMinErr.interr(text, err));
23223            }
23224
23225          }, {
23226          // all of these properties are undocumented for now
23227          exp: text, //just for compatibility with regular watchers created via $watch
23228          expressions: expressions,
23229          $$watchDelegate: function(scope, listener) {
23230            var lastValue;
23231            return scope.$watchGroup(parseFns, /** @this */ function interpolateFnWatcher(values, oldValues) {
23232              var currValue = compute(values);
23233              if (isFunction(listener)) {
23234                listener.call(this, currValue, values !== oldValues ? lastValue : currValue, scope);
23235              }
23236              lastValue = currValue;
23237            });
23238          }
23239        });
23240      }
23241
23242      function parseStringifyInterceptor(value) {
23243        try {
23244          value = getValue(value);
23245          return allOrNothing && !isDefined(value) ? value : stringify(value);
23246        } catch (err) {
23247          $exceptionHandler($interpolateMinErr.interr(text, err));
23248        }
23249      }
23250    }
23251
23252
23253    /**
23254     * @ngdoc method
23255     * @name $interpolate#startSymbol
23256     * @description
23257     * Symbol to denote the start of expression in the interpolated string. Defaults to `{{`.
23258     *
23259     * Use {@link ng.$interpolateProvider#startSymbol `$interpolateProvider.startSymbol`} to change
23260     * the symbol.
23261     *
23262     * @returns {string} start symbol.
23263     */
23264    $interpolate.startSymbol = function() {
23265      return startSymbol;
23266    };
23267
23268
23269    /**
23270     * @ngdoc method
23271     * @name $interpolate#endSymbol
23272     * @description
23273     * Symbol to denote the end of expression in the interpolated string. Defaults to `}}`.
23274     *
23275     * Use {@link ng.$interpolateProvider#endSymbol `$interpolateProvider.endSymbol`} to change
23276     * the symbol.
23277     *
23278     * @returns {string} end symbol.
23279     */
23280    $interpolate.endSymbol = function() {
23281      return endSymbol;
23282    };
23283
23284    return $interpolate;
23285  }];
23286}
23287
23288/** @this */
23289function $IntervalProvider() {
23290  this.$get = ['$rootScope', '$window', '$q', '$$q', '$browser',
23291       function($rootScope,   $window,   $q,   $$q,   $browser) {
23292    var intervals = {};
23293
23294
23295     /**
23296      * @ngdoc service
23297      * @name $interval
23298      *
23299      * @description
23300      * Angular's wrapper for `window.setInterval`. The `fn` function is executed every `delay`
23301      * milliseconds.
23302      *
23303      * The return value of registering an interval function is a promise. This promise will be
23304      * notified upon each tick of the interval, and will be resolved after `count` iterations, or
23305      * run indefinitely if `count` is not defined. The value of the notification will be the
23306      * number of iterations that have run.
23307      * To cancel an interval, call `$interval.cancel(promise)`.
23308      *
23309      * In tests you can use {@link ngMock.$interval#flush `$interval.flush(millis)`} to
23310      * move forward by `millis` milliseconds and trigger any functions scheduled to run in that
23311      * time.
23312      *
23313      * <div class="alert alert-warning">
23314      * **Note**: Intervals created by this service must be explicitly destroyed when you are finished
23315      * with them.  In particular they are not automatically destroyed when a controller's scope or a
23316      * directive's element are destroyed.
23317      * You should take this into consideration and make sure to always cancel the interval at the
23318      * appropriate moment.  See the example below for more details on how and when to do this.
23319      * </div>
23320      *
23321      * @param {function()} fn A function that should be called repeatedly. If no additional arguments
23322      *   are passed (see below), the function is called with the current iteration count.
23323      * @param {number} delay Number of milliseconds between each function call.
23324      * @param {number=} [count=0] Number of times to repeat. If not set, or 0, will repeat
23325      *   indefinitely.
23326      * @param {boolean=} [invokeApply=true] If set to `false` skips model dirty checking, otherwise
23327      *   will invoke `fn` within the {@link ng.$rootScope.Scope#$apply $apply} block.
23328      * @param {...*=} Pass additional parameters to the executed function.
23329      * @returns {promise} A promise which will be notified on each iteration.
23330      *
23331      * @example
23332      * <example module="intervalExample" name="interval-service">
23333      * <file name="index.html">
23334      *   <script>
23335      *     angular.module('intervalExample', [])
23336      *       .controller('ExampleController', ['$scope', '$interval',
23337      *         function($scope, $interval) {
23338      *           $scope.format = 'M/d/yy h:mm:ss a';
23339      *           $scope.blood_1 = 100;
23340      *           $scope.blood_2 = 120;
23341      *
23342      *           var stop;
23343      *           $scope.fight = function() {
23344      *             // Don't start a new fight if we are already fighting
23345      *             if ( angular.isDefined(stop) ) return;
23346      *
23347      *             stop = $interval(function() {
23348      *               if ($scope.blood_1 > 0 && $scope.blood_2 > 0) {
23349      *                 $scope.blood_1 = $scope.blood_1 - 3;
23350      *                 $scope.blood_2 = $scope.blood_2 - 4;
23351      *               } else {
23352      *                 $scope.stopFight();
23353      *               }
23354      *             }, 100);
23355      *           };
23356      *
23357      *           $scope.stopFight = function() {
23358      *             if (angular.isDefined(stop)) {
23359      *               $interval.cancel(stop);
23360      *               stop = undefined;
23361      *             }
23362      *           };
23363      *
23364      *           $scope.resetFight = function() {
23365      *             $scope.blood_1 = 100;
23366      *             $scope.blood_2 = 120;
23367      *           };
23368      *
23369      *           $scope.$on('$destroy', function() {
23370      *             // Make sure that the interval is destroyed too
23371      *             $scope.stopFight();
23372      *           });
23373      *         }])
23374      *       // Register the 'myCurrentTime' directive factory method.
23375      *       // We inject $interval and dateFilter service since the factory method is DI.
23376      *       .directive('myCurrentTime', ['$interval', 'dateFilter',
23377      *         function($interval, dateFilter) {
23378      *           // return the directive link function. (compile function not needed)
23379      *           return function(scope, element, attrs) {
23380      *             var format,  // date format
23381      *                 stopTime; // so that we can cancel the time updates
23382      *
23383      *             // used to update the UI
23384      *             function updateTime() {
23385      *               element.text(dateFilter(new Date(), format));
23386      *             }
23387      *
23388      *             // watch the expression, and update the UI on change.
23389      *             scope.$watch(attrs.myCurrentTime, function(value) {
23390      *               format = value;
23391      *               updateTime();
23392      *             });
23393      *
23394      *             stopTime = $interval(updateTime, 1000);
23395      *
23396      *             // listen on DOM destroy (removal) event, and cancel the next UI update
23397      *             // to prevent updating time after the DOM element was removed.
23398      *             element.on('$destroy', function() {
23399      *               $interval.cancel(stopTime);
23400      *             });
23401      *           }
23402      *         }]);
23403      *   </script>
23404      *
23405      *   <div>
23406      *     <div ng-controller="ExampleController">
23407      *       <label>Date format: <input ng-model="format"></label> <hr/>
23408      *       Current time is: <span my-current-time="format"></span>
23409      *       <hr/>
23410      *       Blood 1 : <font color='red'>{{blood_1}}</font>
23411      *       Blood 2 : <font color='red'>{{blood_2}}</font>
23412      *       <button type="button" data-ng-click="fight()">Fight</button>
23413      *       <button type="button" data-ng-click="stopFight()">StopFight</button>
23414      *       <button type="button" data-ng-click="resetFight()">resetFight</button>
23415      *     </div>
23416      *   </div>
23417      *
23418      * </file>
23419      * </example>
23420      */
23421    function interval(fn, delay, count, invokeApply) {
23422      var hasParams = arguments.length > 4,
23423          args = hasParams ? sliceArgs(arguments, 4) : [],
23424          setInterval = $window.setInterval,
23425          clearInterval = $window.clearInterval,
23426          iteration = 0,
23427          skipApply = (isDefined(invokeApply) && !invokeApply),
23428          deferred = (skipApply ? $$q : $q).defer(),
23429          promise = deferred.promise;
23430
23431      count = isDefined(count) ? count : 0;
23432
23433      promise.$$intervalId = setInterval(function tick() {
23434        if (skipApply) {
23435          $browser.defer(callback);
23436        } else {
23437          $rootScope.$evalAsync(callback);
23438        }
23439        deferred.notify(iteration++);
23440
23441        if (count > 0 && iteration >= count) {
23442          deferred.resolve(iteration);
23443          clearInterval(promise.$$intervalId);
23444          delete intervals[promise.$$intervalId];
23445        }
23446
23447        if (!skipApply) $rootScope.$apply();
23448
23449      }, delay);
23450
23451      intervals[promise.$$intervalId] = deferred;
23452
23453      return promise;
23454
23455      function callback() {
23456        if (!hasParams) {
23457          fn(iteration);
23458        } else {
23459          fn.apply(null, args);
23460        }
23461      }
23462    }
23463
23464
23465     /**
23466      * @ngdoc method
23467      * @name $interval#cancel
23468      *
23469      * @description
23470      * Cancels a task associated with the `promise`.
23471      *
23472      * @param {Promise=} promise returned by the `$interval` function.
23473      * @returns {boolean} Returns `true` if the task was successfully canceled.
23474      */
23475    interval.cancel = function(promise) {
23476      if (promise && promise.$$intervalId in intervals) {
23477        // Interval cancels should not report as unhandled promise.
23478        intervals[promise.$$intervalId].promise.catch(noop);
23479        intervals[promise.$$intervalId].reject('canceled');
23480        $window.clearInterval(promise.$$intervalId);
23481        delete intervals[promise.$$intervalId];
23482        return true;
23483      }
23484      return false;
23485    };
23486
23487    return interval;
23488  }];
23489}
23490
23491/**
23492 * @ngdoc service
23493 * @name $jsonpCallbacks
23494 * @requires $window
23495 * @description
23496 * This service handles the lifecycle of callbacks to handle JSONP requests.
23497 * Override this service if you wish to customise where the callbacks are stored and
23498 * how they vary compared to the requested url.
23499 */
23500var $jsonpCallbacksProvider = /** @this */ function() {
23501  this.$get = function() {
23502    var callbacks = angular.callbacks;
23503    var callbackMap = {};
23504
23505    function createCallback(callbackId) {
23506      var callback = function(data) {
23507        callback.data = data;
23508        callback.called = true;
23509      };
23510      callback.id = callbackId;
23511      return callback;
23512    }
23513
23514    return {
23515      /**
23516       * @ngdoc method
23517       * @name $jsonpCallbacks#createCallback
23518       * @param {string} url the url of the JSONP request
23519       * @returns {string} the callback path to send to the server as part of the JSONP request
23520       * @description
23521       * {@link $httpBackend} calls this method to create a callback and get hold of the path to the callback
23522       * to pass to the server, which will be used to call the callback with its payload in the JSONP response.
23523       */
23524      createCallback: function(url) {
23525        var callbackId = '_' + (callbacks.$$counter++).toString(36);
23526        var callbackPath = 'angular.callbacks.' + callbackId;
23527        var callback = createCallback(callbackId);
23528        callbackMap[callbackPath] = callbacks[callbackId] = callback;
23529        return callbackPath;
23530      },
23531      /**
23532       * @ngdoc method
23533       * @name $jsonpCallbacks#wasCalled
23534       * @param {string} callbackPath the path to the callback that was sent in the JSONP request
23535       * @returns {boolean} whether the callback has been called, as a result of the JSONP response
vendor: 13,793 bytes, lines 23536-24028
23536       * @description
23537       * {@link $httpBackend} calls this method to find out whether the JSONP response actually called the
23538       * callback that was passed in the request.
23539       */
23540      wasCalled: function(callbackPath) {
23541        return callbackMap[callbackPath].called;
23542      },
23543      /**
23544       * @ngdoc method
23545       * @name $jsonpCallbacks#getResponse
23546       * @param {string} callbackPath the path to the callback that was sent in the JSONP request
23547       * @returns {*} the data received from the response via the registered callback
23548       * @description
23549       * {@link $httpBackend} calls this method to get hold of the data that was provided to the callback
23550       * in the JSONP response.
23551       */
23552      getResponse: function(callbackPath) {
23553        return callbackMap[callbackPath].data;
23554      },
23555      /**
23556       * @ngdoc method
23557       * @name $jsonpCallbacks#removeCallback
23558       * @param {string} callbackPath the path to the callback that was sent in the JSONP request
23559       * @description
23560       * {@link $httpBackend} calls this method to remove the callback after the JSONP request has
23561       * completed or timed-out.
23562       */
23563      removeCallback: function(callbackPath) {
23564        var callback = callbackMap[callbackPath];
23565        delete callbacks[callback.id];
23566        delete callbackMap[callbackPath];
23567      }
23568    };
23569  };
23570};
23571
23572/**
23573 * @ngdoc service
23574 * @name $locale
23575 *
23576 * @description
23577 * $locale service provides localization rules for various Angular components. As of right now the
23578 * only public api is:
23579 *
23580 * * `id` – `{string}` – locale id formatted as `languageId-countryId` (e.g. `en-us`)
23581 */
23582
23583var PATH_MATCH = /^([^?#]*)(\?([^#]*))?(#(.*))?$/,
23584    DEFAULT_PORTS = {'http': 80, 'https': 443, 'ftp': 21};
23585var $locationMinErr = minErr('$location');
23586
23587
23588/**
23589 * Encode path using encodeUriSegment, ignoring forward slashes
23590 *
23591 * @param {string} path Path to encode
23592 * @returns {string}
23593 */
23594function encodePath(path) {
23595  var segments = path.split('/'),
23596      i = segments.length;
23597
23598  while (i--) {
23599    segments[i] = encodeUriSegment(segments[i]);
23600  }
23601
23602  return segments.join('/');
23603}
23604
23605function parseAbsoluteUrl(absoluteUrl, locationObj) {
23606  var parsedUrl = urlResolve(absoluteUrl);
23607
23608  locationObj.$$protocol = parsedUrl.protocol;
23609  locationObj.$$host = parsedUrl.hostname;
23610  locationObj.$$port = toInt(parsedUrl.port) || DEFAULT_PORTS[parsedUrl.protocol] || null;
23611}
23612
23613var DOUBLE_SLASH_REGEX = /^\s*[\\/]{2,}/;
23614function parseAppUrl(url, locationObj) {
23615
23616  if (DOUBLE_SLASH_REGEX.test(url)) {
23617    throw $locationMinErr('badpath', 'Invalid url "{0}".', url);
23618  }
23619
23620  var prefixed = (url.charAt(0) !== '/');
23621  if (prefixed) {
23622    url = '/' + url;
23623  }
23624  var match = urlResolve(url);
23625  locationObj.$$path = decodeURIComponent(prefixed && match.pathname.charAt(0) === '/' ?
23626      match.pathname.substring(1) : match.pathname);
23627  locationObj.$$search = parseKeyValue(match.search);
23628  locationObj.$$hash = decodeURIComponent(match.hash);
23629
23630  // make sure path starts with '/';
23631  if (locationObj.$$path && locationObj.$$path.charAt(0) !== '/') {
23632    locationObj.$$path = '/' + locationObj.$$path;
23633  }
23634}
23635
23636function startsWith(str, search) {
23637  return str.slice(0, search.length) === search;
23638}
23639
23640/**
23641 *
23642 * @param {string} base
23643 * @param {string} url
23644 * @returns {string} returns text from `url` after `base` or `undefined` if it does not begin with
23645 *                   the expected string.
23646 */
23647function stripBaseUrl(base, url) {
23648  if (startsWith(url, base)) {
23649    return url.substr(base.length);
23650  }
23651}
23652
23653
23654function stripHash(url) {
23655  var index = url.indexOf('#');
23656  return index === -1 ? url : url.substr(0, index);
23657}
23658
23659function trimEmptyHash(url) {
23660  return url.replace(/(#.+)|#$/, '$1');
23661}
23662
23663
23664function stripFile(url) {
23665  return url.substr(0, stripHash(url).lastIndexOf('/') + 1);
23666}
23667
23668/* return the server only (scheme://host:port) */
23669function serverBase(url) {
23670  return url.substring(0, url.indexOf('/', url.indexOf('//') + 2));
23671}
23672
23673
23674/**
23675 * LocationHtml5Url represents a URL
23676 * This object is exposed as $location service when HTML5 mode is enabled and supported
23677 *
23678 * @constructor
23679 * @param {string} appBase application base URL
23680 * @param {string} appBaseNoFile application base URL stripped of any filename
23681 * @param {string} basePrefix URL path prefix
23682 */
23683function LocationHtml5Url(appBase, appBaseNoFile, basePrefix) {
23684  this.$$html5 = true;
23685  basePrefix = basePrefix || '';
23686  parseAbsoluteUrl(appBase, this);
23687
23688
23689  /**
23690   * Parse given HTML5 (regular) URL string into properties
23691   * @param {string} url HTML5 URL
23692   * @private
23693   */
23694  this.$$parse = function(url) {
23695    var pathUrl = stripBaseUrl(appBaseNoFile, url);
23696    if (!isString(pathUrl)) {
23697      throw $locationMinErr('ipthprfx', 'Invalid url "{0}", missing path prefix "{1}".', url,
23698          appBaseNoFile);
23699    }
23700
23701    parseAppUrl(pathUrl, this);
23702
23703    if (!this.$$path) {
23704      this.$$path = '/';
23705    }
23706
23707    this.$$compose();
23708  };
23709
23710  /**
23711   * Compose url and update `absUrl` property
23712   * @private
23713   */
23714  this.$$compose = function() {
23715    var search = toKeyValue(this.$$search),
23716        hash = this.$$hash ? '#' + encodeUriSegment(this.$$hash) : '';
23717
23718    this.$$url = encodePath(this.$$path) + (search ? '?' + search : '') + hash;
23719    this.$$absUrl = appBaseNoFile + this.$$url.substr(1); // first char is always '/'
23720
23721    this.$$urlUpdatedByLocation = true;
23722  };
23723
23724  this.$$parseLinkUrl = function(url, relHref) {
23725    if (relHref && relHref[0] === '#') {
23726      // special case for links to hash fragments:
23727      // keep the old url and only replace the hash fragment
23728      this.hash(relHref.slice(1));
23729      return true;
23730    }
23731    var appUrl, prevAppUrl;
23732    var rewrittenUrl;
23733
23734
23735    if (isDefined(appUrl = stripBaseUrl(appBase, url))) {
23736      prevAppUrl = appUrl;
23737      if (basePrefix && isDefined(appUrl = stripBaseUrl(basePrefix, appUrl))) {
23738        rewrittenUrl = appBaseNoFile + (stripBaseUrl('/', appUrl) || appUrl);
23739      } else {
23740        rewrittenUrl = appBase + prevAppUrl;
23741      }
23742    } else if (isDefined(appUrl = stripBaseUrl(appBaseNoFile, url))) {
23743      rewrittenUrl = appBaseNoFile + appUrl;
23744    } else if (appBaseNoFile === url + '/') {
23745      rewrittenUrl = appBaseNoFile;
23746    }
23747    if (rewrittenUrl) {
23748      this.$$parse(rewrittenUrl);
23749    }
23750    return !!rewrittenUrl;
23751  };
23752}
23753
23754
23755/**
23756 * LocationHashbangUrl represents URL
23757 * This object is exposed as $location service when developer doesn't opt into html5 mode.
23758 * It also serves as the base class for html5 mode fallback on legacy browsers.
23759 *
23760 * @constructor
23761 * @param {string} appBase application base URL
23762 * @param {string} appBaseNoFile application base URL stripped of any filename
23763 * @param {string} hashPrefix hashbang prefix
23764 */
23765function LocationHashbangUrl(appBase, appBaseNoFile, hashPrefix) {
23766
23767  parseAbsoluteUrl(appBase, this);
23768
23769
23770  /**
23771   * Parse given hashbang URL into properties
23772   * @param {string} url Hashbang URL
23773   * @private
23774   */
23775  this.$$parse = function(url) {
23776    var withoutBaseUrl = stripBaseUrl(appBase, url) || stripBaseUrl(appBaseNoFile, url);
23777    var withoutHashUrl;
23778
23779    if (!isUndefined(withoutBaseUrl) && withoutBaseUrl.charAt(0) === '#') {
23780
23781      // The rest of the URL starts with a hash so we have
23782      // got either a hashbang path or a plain hash fragment
23783      withoutHashUrl = stripBaseUrl(hashPrefix, withoutBaseUrl);
23784      if (isUndefined(withoutHashUrl)) {
23785        // There was no hashbang prefix so we just have a hash fragment
23786        withoutHashUrl = withoutBaseUrl;
23787      }
23788
23789    } else {
23790      // There was no hashbang path nor hash fragment:
23791      // If we are in HTML5 mode we use what is left as the path;
23792      // Otherwise we ignore what is left
23793      if (this.$$html5) {
23794        withoutHashUrl = withoutBaseUrl;
23795      } else {
23796        withoutHashUrl = '';
23797        if (isUndefined(withoutBaseUrl)) {
23798          appBase = url;
23799          /** @type {?} */ (this).replace();
23800        }
23801      }
23802    }
23803
23804    parseAppUrl(withoutHashUrl, this);
23805
23806    this.$$path = removeWindowsDriveName(this.$$path, withoutHashUrl, appBase);
23807
23808    this.$$compose();
23809
23810    /*
23811     * In Windows, on an anchor node on documents loaded from
23812     * the filesystem, the browser will return a pathname
23813     * prefixed with the drive name ('/C:/path') when a
23814     * pathname without a drive is set:
23815     *  * a.setAttribute('href', '/foo')
23816     *   * a.pathname === '/C:/foo' //true
23817     *
23818     * Inside of Angular, we're always using pathnames that
23819     * do not include drive names for routing.
23820     */
23821    function removeWindowsDriveName(path, url, base) {
23822      /*
23823      Matches paths for file protocol on windows,
23824      such as /C:/foo/bar, and captures only /foo/bar.
23825      */
23826      var windowsFilePathExp = /^\/[A-Z]:(\/.*)/;
23827
23828      var firstPathSegmentMatch;
23829
23830      //Get the relative path from the input URL.
23831      if (startsWith(url, base)) {
23832        url = url.replace(base, '');
23833      }
23834
23835      // The input URL intentionally contains a first path segment that ends with a colon.
23836      if (windowsFilePathExp.exec(url)) {
23837        return path;
23838      }
23839
23840      firstPathSegmentMatch = windowsFilePathExp.exec(path);
23841      return firstPathSegmentMatch ? firstPathSegmentMatch[1] : path;
23842    }
23843  };
23844
23845  /**
23846   * Compose hashbang URL and update `absUrl` property
23847   * @private
23848   */
23849  this.$$compose = function() {
23850    var search = toKeyValue(this.$$search),
23851        hash = this.$$hash ? '#' + encodeUriSegment(this.$$hash) : '';
23852
23853    this.$$url = encodePath(this.$$path) + (search ? '?' + search : '') + hash;
23854    this.$$absUrl = appBase + (this.$$url ? hashPrefix + this.$$url : '');
23855
23856    this.$$urlUpdatedByLocation = true;
23857  };
23858
23859  this.$$parseLinkUrl = function(url, relHref) {
23860    if (stripHash(appBase) === stripHash(url)) {
23861      this.$$parse(url);
23862      return true;
23863    }
23864    return false;
23865  };
23866}
23867
23868
23869/**
23870 * LocationHashbangUrl represents URL
23871 * This object is exposed as $location service when html5 history api is enabled but the browser
23872 * does not support it.
23873 *
23874 * @constructor
23875 * @param {string} appBase application base URL
23876 * @param {string} appBaseNoFile application base URL stripped of any filename
23877 * @param {string} hashPrefix hashbang prefix
23878 */
23879function LocationHashbangInHtml5Url(appBase, appBaseNoFile, hashPrefix) {
23880  this.$$html5 = true;
23881  LocationHashbangUrl.apply(this, arguments);
23882
23883  this.$$parseLinkUrl = function(url, relHref) {
23884    if (relHref && relHref[0] === '#') {
23885      // special case for links to hash fragments:
23886      // keep the old url and only replace the hash fragment
23887      this.hash(relHref.slice(1));
23888      return true;
23889    }
23890
23891    var rewrittenUrl;
23892    var appUrl;
23893
23894    if (appBase === stripHash(url)) {
23895      rewrittenUrl = url;
23896    } else if ((appUrl = stripBaseUrl(appBaseNoFile, url))) {
23897      rewrittenUrl = appBase + hashPrefix + appUrl;
23898    } else if (appBaseNoFile === url + '/') {
23899      rewrittenUrl = appBaseNoFile;
23900    }
23901    if (rewrittenUrl) {
23902      this.$$parse(rewrittenUrl);
23903    }
23904    return !!rewrittenUrl;
23905  };
23906
23907  this.$$compose = function() {
23908    var search = toKeyValue(this.$$search),
23909        hash = this.$$hash ? '#' + encodeUriSegment(this.$$hash) : '';
23910
23911    this.$$url = encodePath(this.$$path) + (search ? '?' + search : '') + hash;
23912    // include hashPrefix in $$absUrl when $$url is empty so IE9 does not reload page because of removal of '#'
23913    this.$$absUrl = appBase + hashPrefix + this.$$url;
23914
23915    this.$$urlUpdatedByLocation = true;
23916  };
23917
23918}
23919
23920
23921var locationPrototype = {
23922
23923  /**
23924   * Ensure absolute URL is initialized.
23925   * @private
23926   */
23927  $$absUrl:'',
23928
23929  /**
23930   * Are we in html5 mode?
23931   * @private
23932   */
23933  $$html5: false,
23934
23935  /**
23936   * Has any change been replacing?
23937   * @private
23938   */
23939  $$replace: false,
23940
23941  /**
23942   * @ngdoc method
23943   * @name $location#absUrl
23944   *
23945   * @description
23946   * This method is getter only.
23947   *
23948   * Return full URL representation with all segments encoded according to rules specified in
23949   * [RFC 3986](http://www.ietf.org/rfc/rfc3986.txt).
23950   *
23951   *
23952   * ```js
23953   * // given URL http://example.com/#/some/path?foo=bar&baz=xoxo
23954   * var absUrl = $location.absUrl();
23955   * // => "http://example.com/#/some/path?foo=bar&baz=xoxo"
23956   * ```
23957   *
23958   * @return {string} full URL
23959   */
23960  absUrl: locationGetter('$$absUrl'),
23961
23962  /**
23963   * @ngdoc method
23964   * @name $location#url
23965   *
23966   * @description
23967   * This method is getter / setter.
23968   *
23969   * Return URL (e.g. `/path?a=b#hash`) when called without any parameter.
23970   *
23971   * Change path, search and hash, when called with parameter and return `$location`.
23972   *
23973   *
23974   * ```js
23975   * // given URL http://example.com/#/some/path?foo=bar&baz=xoxo
23976   * var url = $location.url();
23977   * // => "/some/path?foo=bar&baz=xoxo"
23978   * ```
23979   *
23980   * @param {string=} url New URL without base prefix (e.g. `/path?a=b#hash`)
23981   * @return {string} url
23982   */
23983  url: function(url) {
23984    if (isUndefined(url)) {
23985      return this.$$url;
23986    }
23987
23988    var match = PATH_MATCH.exec(url);
23989    if (match[1] || url === '') this.path(decodeURIComponent(match[1]));
23990    if (match[2] || match[1] || url === '') this.search(match[3] || '');
23991    this.hash(match[5] || '');
23992
23993    return this;
23994  },
23995
23996  /**
23997   * @ngdoc method
23998   * @name $location#protocol
23999   *
24000   * @description
24001   * This method is getter only.
24002   *
24003   * Return protocol of current URL.
24004   *
24005   *
24006   * ```js
24007   * // given URL http://example.com/#/some/path?foo=bar&baz=xoxo
24008   * var protocol = $location.protocol();
24009   * // => "http"
24010   * ```
24011   *
24012   * @return {string} protocol of current URL
24013   */
24014  protocol: locationGetter('$$protocol'),
24015
24016  /**
24017   * @ngdoc method
24018   * @name $location#host
24019   *
24020   * @description
24021   * This method is getter only.
24022   *
24023   * Return host of current URL.
24024   *
24025   * Note: compared to the non-angular version `location.host` which returns `hostname:port`, this returns the `hostname` portion only.
24026   *
24027   *
24028   * ```js
24029   * // given URL http://example.com/#/some/path?foo=bar&baz=xoxo
24030   * var host = $location.host();
24031   * // => "example.com"
24032   *
24033   * // given URL http://user:[email protected]:8080/#/some/path?foo=bar&baz=xoxo
24034   * host = $location.host();
24035   * // => "example.com"
24036   * host = location.host;
24037   * // => "example.com:8080"
24038   * ```
24039   *
24040   * @return {string} host of current URL.
24041   */
24042  host: locationGetter('$$host'),
24043
24044  /**
24045   * @ngdoc method
24046   * @name $location#port
24047   *
24048   * @description
24049   * This method is getter only.
24050   *
24051   * Return port of current URL.
24052   *
24053   *
24054   * ```js
24055   * // given URL http://example.com/#/some/path?foo=bar&baz=xoxo
24056   * var port = $location.port();
24057   * // => 80
24058   * ```
24059   *
24060   * @return {Number} port
24061   */
24062  port: locationGetter('$$port'),
24063
24064  /**
24065   * @ngdoc method
24066   * @name $location#path
24067   *
24068   * @description
24069   * This method is getter / setter.
24070   *
24071   * Return path of current URL when called without any parameter.
24072   *
24073   * Change path when called with parameter and return `$location`.
24074   *
24075   * Note: Path should always begin with forward slash (/), this method will add the forward slash
24076   * if it is missing.
24077   *
24078   *
24079   * ```js
24080   * // given URL http://example.com/#/some/path?foo=bar&baz=xoxo
24081   * var path = $location.path();
24082   * // => "/some/path"
24083   * ```
24084   *
24085   * @param {(string|number)=} path New path
24086   * @return {(string|object)} path if called with no parameters, or `$location` if called with a parameter
24087   */
24088  path: locationGetterSetter('$$path', function(path) {
24089    path = path !== null ? path.toString() : '';
24090    return path.charAt(0) === '/' ? path : '/' + path;
24091  }),
24092
24093  /**
24094   * @ngdoc method
24095   * @name $location#search
24096   *
24097   * @description
24098   * This method is getter / setter.
24099   *
24100   * Return search part (as object) of current URL when called without any parameter.
24101   *
24102   * Change search part when called with parameter and return `$location`.
24103   *
24104   *
24105   * ```js
24106   * // given URL http://example.com/#/some/path?foo=bar&baz=xoxo
24107   * var searchObject = $location.search();
24108   * // => {foo: 'bar', baz: 'xoxo'}
24109   *
24110   * // set foo to 'yipee'
24111   * $location.search('foo', 'yipee');
24112   * // $location.search() => {foo: 'yipee', baz: 'xoxo'}
24113   * ```
24114   *
24115   * @param {string|Object.<string>|Object.<Array.<string>>} search New search params - string or
24116   * hash object.
24117   *
24118   * When called with a single argument the method acts as a setter, setting the `search` component
24119   * of `$location` to the specified value.
24120   *
24121   * If the argument is a hash object containing an array of values, these values will be encoded
24122   * as duplicate search parameters in the URL.
24123   *
24124   * @param {(string|Number|Array<string>|boolean)=} paramValue If `search` is a string or number, then `paramValue`
24125   * will override only a single search property.
24126   *
24127   * If `paramValue` is an array, it will override the property of the `search` component of
24128   * `$location` specified via the first argument.
24129   *
24130   * If `paramValue` is `null`, the property specified via the first argument will be deleted.
24131   *
24132   * If `paramValue` is `true`, the property specified via the first argument will be added with no
24133   * value nor trailing equal sign.
24134   *
24135   * @return {Object} If called with no arguments returns the parsed `search` object. If called with
24136   * one or more arguments returns `$location` object itself.
24137   */
24138  search: function(search, paramValue) {
24139    switch (arguments.length) {
24140      case 0:
24141        return this.$$search;
24142      case 1:
24143        if (isString(search) || isNumber(search)) {
24144          search = search.toString();
24145          this.$$search = parseKeyValue(search);
24146        } else if (isObject(search)) {
24147          search = copy(search, {});
24148          // remove object undefined or null properties
24149          forEach(search, function(value, key) {
24150            if (value == null) delete search[key];
24151          });
24152
24153          this.$$search = search;
24154        } else {
24155          throw $locationMinErr('isrcharg',
24156              'The first argument of the `$location#search()` call must be a string or an object.');
24157        }
24158        break;
24159      default:
24160        if (isUndefined(paramValue) || paramValue === null) {
24161          delete this.$$search[search];
24162        } else {
24163          this.$$search[search] = paramValue;
24164        }
24165    }
24166
24167    this.$$compose();
24168    return this;
24169  },
24170
24171  /**
24172   * @ngdoc method
24173   * @name $location#hash
24174   *
24175   * @description
24176   * This method is getter / setter.
24177   *
24178   * Returns the hash fragment when called without any parameters.
24179   *
24180   * Changes the hash fragment when called with a parameter and returns `$location`.
24181   *
24182   *
24183   * ```js
24184   * // given URL http://example.com/#/some/path?foo=bar&baz=xoxo#hashValue
24185   * var hash = $location.hash();
24186   * // => "hashValue"
24187   * ```
24188   *
24189   * @param {(string|number)=} hash New hash fragment
24190   * @return {string} hash
24191   */
24192  hash: locationGetterSetter('$$hash', function(hash) {
24193    return hash !== null ? hash.toString() : '';
24194  }),
24195
24196  /**
24197   * @ngdoc method
24198   * @name $location#replace
24199   *
24200   * @description
24201   * If called, all changes to $location during the current `$digest` will replace the current history
24202   * record, instead of adding a new one.
24203   */
24204  replace: function() {
24205    this.$$replace = true;
24206    return this;
24207  }
24208};
24209
24210forEach([LocationHashbangInHtml5Url, LocationHashbangUrl, LocationHtml5Url], function(Location) {
24211  Location.prototype = Object.create(locationPrototype);
24212
24213  /**
24214   * @ngdoc method
24215   * @name $location#state
24216   *
24217   * @description
24218   * This method is getter / setter.
24219   *
24220   * Return the history state object when called without any parameter.
24221   *
24222   * Change the history state object when called with one parameter and return `$location`.
24223   * The state object is later passed to `pushState` or `replaceState`.
24224   *
24225   * NOTE: This method is supported only in HTML5 mode and only in browsers supporting
24226   * the HTML5 History API (i.e. methods `pushState` and `replaceState`). If you need to support
24227   * older browsers (like IE9 or Android < 4.0), don't use this method.
24228   *
24229   * @param {object=} state State object for pushState or replaceState
24230   * @return {object} state
24231   */
24232  Location.prototype.state = function(state) {
24233    if (!arguments.length) {
24234      return this.$$state;
24235    }
24236
24237    if (Location !== LocationHtml5Url || !this.$$html5) {
24238      throw $locationMinErr('nostate', 'History API state support is available only ' +
24239        'in HTML5 mode and only in browsers supporting HTML5 History API');
24240    }
24241    // The user might modify `stateObject` after invoking `$location.state(stateObject)`
24242    // but we're changing the $$state reference to $browser.state() during the $digest
24243    // so the modification window is narrow.
24244    this.$$state = isUndefined(state) ? null : state;
24245    this.$$urlUpdatedByLocation = true;
24246
24247    return this;
24248  };
24249});
24250
24251
24252function locationGetter(property) {
24253  return /** @this */ function() {
24254    return this[property];
24255  };
24256}
24257
24258
24259function locationGetterSetter(property, preprocess) {
24260  return /** @this */ function(value) {
24261    if (isUndefined(value)) {
24262      return this[property];
24263    }
24264
24265    this[property] = preprocess(value);
24266    this.$$compose();
24267
24268    return this;
24269  };
24270}
24271
24272
24273/**
24274 * @ngdoc service
24275 * @name $location
24276 *
24277 * @requires $rootElement
24278 *
24279 * @description
24280 * The $location service parses the URL in the browser address bar (based on the
24281 * [window.location](https://developer.mozilla.org/en/window.location)) and makes the URL
24282 * available to your application. Changes to the URL in the address bar are reflected into
24283 * $location service and changes to $location are reflected into the browser address bar.
24284 *
24285 * **The $location service:**
24286 *
24287 * - Exposes the current URL in the browser address bar, so you can
24288 *   - Watch and observe the URL.
24289 *   - Change the URL.
24290 * - Synchronizes the URL with the browser when the user
24291 *   - Changes the address bar.
24292 *   - Clicks the back or forward button (or clicks a History link).
24293 *   - Clicks on a link.
24294 * - Represents the URL object as a set of methods (protocol, host, port, path, search, hash).
24295 *
24296 * For more information see {@link guide/$location Developer Guide: Using $location}
24297 */
24298
24299/**
24300 * @ngdoc provider
24301 * @name $locationProvider
24302 * @this
24303 *
24304 * @description
24305 * Use the `$locationProvider` to configure how the application deep linking paths are stored.
24306 */
24307function $LocationProvider() {
24308  var hashPrefix = '!',
24309      html5Mode = {
24310        enabled: false,
24311        requireBase: true,
24312        rewriteLinks: true
24313      };
24314
24315  /**
24316   * @ngdoc method
24317   * @name $locationProvider#hashPrefix
24318   * @description
24319   * The default value for the prefix is `'!'`.
24320   * @param {string=} prefix Prefix for hash part (containing path and search)
24321   * @returns {*} current value if used as getter or itself (chaining) if used as setter
24322   */
24323  this.hashPrefix = function(prefix) {
24324    if (isDefined(prefix)) {
24325      hashPrefix = prefix;
24326      return this;
24327    } else {
24328      return hashPrefix;
24329    }
24330  };
24331
24332  /**
24333   * @ngdoc method
24334   * @name $locationProvider#html5Mode
24335   * @description
24336   * @param {(boolean|Object)=} mode If boolean, sets `html5Mode.enabled` to value.
24337   *   If object, sets `enabled`, `requireBase` and `rewriteLinks` to respective values. Supported
24338   *   properties:
24339   *   - **enabled** – `{boolean}` – (default: false) If true, will rely on `history.pushState` to
24340   *     change urls where supported. Will fall back to hash-prefixed paths in browsers that do not
24341   *     support `pushState`.
24342   *   - **requireBase** - `{boolean}` - (default: `true`) When html5Mode is enabled, specifies
24343   *     whether or not a <base> tag is required to be present. If `enabled` and `requireBase` are
24344   *     true, and a base tag is not present, an error will be thrown when `$location` is injected.
24345   *     See the {@link guide/$location $location guide for more information}
24346   *   - **rewriteLinks** - `{boolean|string}` - (default: `true`) When html5Mode is enabled,
24347   *     enables/disables URL rewriting for relative links. If set to a string, URL rewriting will
24348   *     only happen on links with an attribute that matches the given string. For example, if set
24349   *     to `'internal-link'`, then the URL will only be rewritten for `<a internal-link>` links.
24350   *     Note that [attribute name normalization](guide/directive#normalization) does not apply
24351   *     here, so `'internalLink'` will **not** match `'internal-link'`.
24352   *
24353   * @returns {Object} html5Mode object if used as getter or itself (chaining) if used as setter
24354   */
24355  this.html5Mode = function(mode) {
24356    if (isBoolean(mode)) {
24357      html5Mode.enabled = mode;
24358      return this;
24359    } else if (isObject(mode)) {
24360
24361      if (isBoolean(mode.enabled)) {
24362        html5Mode.enabled = mode.enabled;
24363      }
24364
24365      if (isBoolean(mode.requireBase)) {
24366        html5Mode.requireBase = mode.requireBase;
24367      }
24368
24369      if (isBoolean(mode.rewriteLinks) || isString(mode.rewriteLinks)) {
24370        html5Mode.rewriteLinks = mode.rewriteLinks;
24371      }
24372
24373      return this;
24374    } else {
24375      return html5Mode;
24376    }
24377  };
24378
24379  /**
24380   * @ngdoc event
24381   * @name $location#$locationChangeStart
24382   * @eventType broadcast on root scope
24383   * @description
24384   * Broadcasted before a URL will change.
24385   *
24386   * This change can be prevented by calling
24387   * `preventDefault` method of the event. See {@link ng.$rootScope.Scope#$on} for more
24388   * details about event object. Upon successful change
24389   * {@link ng.$location#$locationChangeSuccess $locationChangeSuccess} is fired.
24390   *
24391   * The `newState` and `oldState` parameters may be defined only in HTML5 mode and when
24392   * the browser supports the HTML5 History API.
24393   *
24394   * @param {Object} angularEvent Synthetic event object.
24395   * @param {string} newUrl New URL
24396   * @param {string=} oldUrl URL that was before it was changed.
24397   * @param {string=} newState New history state object
24398   * @param {string=} oldState History state object that was before it was changed.
24399   */
24400
24401  /**
24402   * @ngdoc event
24403   * @name $location#$locationChangeSuccess
24404   * @eventType broadcast on root scope
24405   * @description
24406   * Broadcasted after a URL was changed.
24407   *
24408   * The `newState` and `oldState` parameters may be defined only in HTML5 mode and when
24409   * the browser supports the HTML5 History API.
24410   *
24411   * @param {Object} angularEvent Synthetic event object.
24412   * @param {string} newUrl New URL
24413   * @param {string=} oldUrl URL that was before it was changed.
24414   * @param {string=} newState New history state object
24415   * @param {string=} oldState History state object that was before it was changed.
24416   */
24417
24418  this.$get = ['$rootScope', '$browser', '$sniffer', '$rootElement', '$window',
24419      function($rootScope, $browser, $sniffer, $rootElement, $window) {
24420    var $location,
24421        LocationMode,
24422        baseHref = $browser.baseHref(), // if base[href] is undefined, it defaults to ''
24423        initialUrl = $browser.url(),
24424        appBase;
24425
24426    if (html5Mode.enabled) {
24427      if (!baseHref && html5Mode.requireBase) {
24428        throw $locationMinErr('nobase',
24429          '$location in HTML5 mode requires a <base> tag to be present!');
24430      }
24431      appBase = serverBase(initialUrl) + (baseHref || '/');
24432      LocationMode = $sniffer.history ? LocationHtml5Url : LocationHashbangInHtml5Url;
24433    } else {
24434      appBase = stripHash(initialUrl);
24435      LocationMode = LocationHashbangUrl;
24436    }
24437    var appBaseNoFile = stripFile(appBase);
24438
vendor: 9,011 bytes, lines 24439-24689
24439    $location = new LocationMode(appBase, appBaseNoFile, '#' + hashPrefix);
24440    $location.$$parseLinkUrl(initialUrl, initialUrl);
24441
24442    $location.$$state = $browser.state();
24443
24444    var IGNORE_URI_REGEXP = /^\s*(javascript|mailto):/i;
24445
24446    function setBrowserUrlWithFallback(url, replace, state) {
24447      var oldUrl = $location.url();
24448      var oldState = $location.$$state;
24449      try {
24450        $browser.url(url, replace, state);
24451
24452        // Make sure $location.state() returns referentially identical (not just deeply equal)
24453        // state object; this makes possible quick checking if the state changed in the digest
24454        // loop. Checking deep equality would be too expensive.
24455        $location.$$state = $browser.state();
24456      } catch (e) {
24457        // Restore old values if pushState fails
24458        $location.url(oldUrl);
24459        $location.$$state = oldState;
24460
24461        throw e;
24462      }
24463    }
24464
24465    $rootElement.on('click', function(event) {
24466      var rewriteLinks = html5Mode.rewriteLinks;
24467      // TODO(vojta): rewrite link when opening in new tab/window (in legacy browser)
24468      // currently we open nice url link and redirect then
24469
24470      if (!rewriteLinks || event.ctrlKey || event.metaKey || event.shiftKey || event.which === 2 || event.button === 2) return;
24471
24472      var elm = jqLite(event.target);
24473
24474      // traverse the DOM up to find first A tag
24475      while (nodeName_(elm[0]) !== 'a') {
24476        // ignore rewriting if no A tag (reached root element, or no parent - removed from document)
24477        if (elm[0] === $rootElement[0] || !(elm = elm.parent())[0]) return;
24478      }
24479
24480      if (isString(rewriteLinks) && isUndefined(elm.attr(rewriteLinks))) return;
24481
24482      var absHref = elm.prop('href');
24483      // get the actual href attribute - see
24484      // http://msdn.microsoft.com/en-us/library/ie/dd347148(v=vs.85).aspx
24485      var relHref = elm.attr('href') || elm.attr('xlink:href');
24486
24487      if (isObject(absHref) && absHref.toString() === '[object SVGAnimatedString]') {
24488        // SVGAnimatedString.animVal should be identical to SVGAnimatedString.baseVal, unless during
24489        // an animation.
24490        absHref = urlResolve(absHref.animVal).href;
24491      }
24492
24493      // Ignore when url is started with javascript: or mailto:
24494      if (IGNORE_URI_REGEXP.test(absHref)) return;
24495
24496      if (absHref && !elm.attr('target') && !event.isDefaultPrevented()) {
24497        if ($location.$$parseLinkUrl(absHref, relHref)) {
24498          // We do a preventDefault for all urls that are part of the angular application,
24499          // in html5mode and also without, so that we are able to abort navigation without
24500          // getting double entries in the location history.
24501          event.preventDefault();
24502          // update location manually
24503          if ($location.absUrl() !== $browser.url()) {
24504            $rootScope.$apply();
24505            // hack to work around FF6 bug 684208 when scenario runner clicks on links
24506            $window.angular['ff-684208-preventDefault'] = true;
24507          }
24508        }
24509      }
24510    });
24511
24512
24513    // rewrite hashbang url <> html5 url
24514    if (trimEmptyHash($location.absUrl()) !== trimEmptyHash(initialUrl)) {
24515      $browser.url($location.absUrl(), true);
24516    }
24517
24518    var initializing = true;
24519
24520    // update $location when $browser url changes
24521    $browser.onUrlChange(function(newUrl, newState) {
24522
24523      if (!startsWith(newUrl, appBaseNoFile)) {
24524        // If we are navigating outside of the app then force a reload
24525        $window.location.href = newUrl;
24526        return;
24527      }
24528
24529      $rootScope.$evalAsync(function() {
24530        var oldUrl = $location.absUrl();
24531        var oldState = $location.$$state;
24532        var defaultPrevented;
24533        newUrl = trimEmptyHash(newUrl);
24534        $location.$$parse(newUrl);
24535        $location.$$state = newState;
24536
24537        defaultPrevented = $rootScope.$broadcast('$locationChangeStart', newUrl, oldUrl,
24538            newState, oldState).defaultPrevented;
24539
24540        // if the location was changed by a `$locationChangeStart` handler then stop
24541        // processing this location change
24542        if ($location.absUrl() !== newUrl) return;
24543
24544        if (defaultPrevented) {
24545          $location.$$parse(oldUrl);
24546          $location.$$state = oldState;
24547          setBrowserUrlWithFallback(oldUrl, false, oldState);
24548        } else {
24549          initializing = false;
24550          afterLocationChange(oldUrl, oldState);
24551        }
24552      });
24553      if (!$rootScope.$$phase) $rootScope.$digest();
24554    });
24555
24556    // update browser
24557    $rootScope.$watch(function $locationWatch() {
24558      if (initializing || $location.$$urlUpdatedByLocation) {
24559        $location.$$urlUpdatedByLocation = false;
24560
24561        var oldUrl = trimEmptyHash($browser.url());
24562        var newUrl = trimEmptyHash($location.absUrl());
24563        var oldState = $browser.state();
24564        var currentReplace = $location.$$replace;
24565        var urlOrStateChanged = oldUrl !== newUrl ||
24566          ($location.$$html5 && $sniffer.history && oldState !== $location.$$state);
24567
24568        if (initializing || urlOrStateChanged) {
24569          initializing = false;
24570
24571          $rootScope.$evalAsync(function() {
24572            var newUrl = $location.absUrl();
24573            var defaultPrevented = $rootScope.$broadcast('$locationChangeStart', newUrl, oldUrl,
24574                $location.$$state, oldState).defaultPrevented;
24575
24576            // if the location was changed by a `$locationChangeStart` handler then stop
24577            // processing this location change
24578            if ($location.absUrl() !== newUrl) return;
24579
24580            if (defaultPrevented) {
24581              $location.$$parse(oldUrl);
24582              $location.$$state = oldState;
24583            } else {
24584              if (urlOrStateChanged) {
24585                setBrowserUrlWithFallback(newUrl, currentReplace,
24586                                          oldState === $location.$$state ? null : $location.$$state);
24587              }
24588              afterLocationChange(oldUrl, oldState);
24589            }
24590          });
24591        }
24592      }
24593
24594      $location.$$replace = false;
24595
24596      // we don't need to return anything because $evalAsync will make the digest loop dirty when
24597      // there is a change
24598    });
24599
24600    return $location;
24601
24602    function afterLocationChange(oldUrl, oldState) {
24603      $rootScope.$broadcast('$locationChangeSuccess', $location.absUrl(), oldUrl,
24604        $location.$$state, oldState);
24605    }
24606}];
24607}
24608
24609/**
24610 * @ngdoc service
24611 * @name $log
24612 * @requires $window
24613 *
24614 * @description
24615 * Simple service for logging. Default implementation safely writes the message
24616 * into the browser's console (if present).
24617 *
24618 * The main purpose of this service is to simplify debugging and troubleshooting.
24619 *
24620 * The default is to log `debug` messages. You can use
24621 * {@link ng.$logProvider ng.$logProvider#debugEnabled} to change this.
24622 *
24623 * @example
24624   <example module="logExample" name="log-service">
24625     <file name="script.js">
24626       angular.module('logExample', [])
24627         .controller('LogController', ['$scope', '$log', function($scope, $log) {
24628           $scope.$log = $log;
24629           $scope.message = 'Hello World!';
24630         }]);
24631     </file>
24632     <file name="index.html">
24633       <div ng-controller="LogController">
24634         <p>Reload this page with open console, enter text and hit the log button...</p>
24635         <label>Message:
24636         <input type="text" ng-model="message" /></label>
24637         <button ng-click="$log.log(message)">log</button>
24638         <button ng-click="$log.warn(message)">warn</button>
24639         <button ng-click="$log.info(message)">info</button>
24640         <button ng-click="$log.error(message)">error</button>
24641         <button ng-click="$log.debug(message)">debug</button>
24642       </div>
24643     </file>
24644   </example>
24645 */
24646
24647/**
24648 * @ngdoc provider
24649 * @name $logProvider
24650 * @this
24651 *
24652 * @description
24653 * Use the `$logProvider` to configure how the application logs messages
24654 */
24655function $LogProvider() {
24656  var debug = true,
24657      self = this;
24658
24659  /**
24660   * @ngdoc method
24661   * @name $logProvider#debugEnabled
24662   * @description
24663   * @param {boolean=} flag enable or disable debug level messages
24664   * @returns {*} current value if used as getter or itself (chaining) if used as setter
24665   */
24666  this.debugEnabled = function(flag) {
24667    if (isDefined(flag)) {
24668      debug = flag;
24669      return this;
24670    } else {
24671      return debug;
24672    }
24673  };
24674
24675  this.$get = ['$window', function($window) {
24676    // Support: IE 9-11, Edge 12-14+
24677    // IE/Edge display errors in such a way that it requires the user to click in 4 places
24678    // to see the stack trace. There is no way to feature-detect it so there's a chance
24679    // of the user agent sniffing to go wrong but since it's only about logging, this shouldn't
24680    // break apps. Other browsers display errors in a sensible way and some of them map stack
24681    // traces along source maps if available so it makes sense to let browsers display it
24682    // as they want.
24683    var formatStackTrace = msie || /\bEdge\//.test($window.navigator && $window.navigator.userAgent);
24684
24685    return {
24686      /**
24687       * @ngdoc method
24688       * @name $log#log
24689       *
24690       * @description
24691       * Write a log message
24692       */
24693      log: consoleLog('log'),
24694
24695      /**
24696       * @ngdoc method
24697       * @name $log#info
24698       *
24699       * @description
24700       * Write an information message
24701       */
24702      info: consoleLog('info'),
24703
24704      /**
24705       * @ngdoc method
24706       * @name $log#warn
24707       *
24708       * @description
24709       * Write a warning message
24710       */
24711      warn: consoleLog('warn'),
24712
24713      /**
24714       * @ngdoc method
24715       * @name $log#error
24716       *
24717       * @description
24718       * Write an error message
24719       */
24720      error: consoleLog('error'),
24721
24722      /**
24723       * @ngdoc method
24724       * @name $log#debug
24725       *
24726       * @description
24727       * Write a debug message
24728       */
24729      debug: (function() {
24730        var fn = consoleLog('debug');
24731
24732        return function() {
24733          if (debug) {
24734            fn.apply(self, arguments);
24735          }
24736        };
24737      })()
24738    };
24739
24740    function formatError(arg) {
24741      if (arg instanceof Error) {
24742        if (arg.stack && formatStackTrace) {
24743          arg = (arg.message && arg.stack.indexOf(arg.message) === -1)
24744              ? 'Error: ' + arg.message + '\n' + arg.stack
24745              : arg.stack;
24746        } else if (arg.sourceURL) {
24747          arg = arg.message + '\n' + arg.sourceURL + ':' + arg.line;
24748        }
24749      }
24750      return arg;
24751    }
24752
24753    function consoleLog(type) {
24754      var console = $window.console || {},
24755          logFn = console[type] || console.log || noop,
24756          hasApply = false;
24757
24758      // Note: reading logFn.apply throws an error in IE11 in IE8 document mode.
24759      // The reason behind this is that console.log has type "object" in IE8...
24760      try {
24761        hasApply = !!logFn.apply;
24762      } catch (e) { /* empty */ }
24763
24764      if (hasApply) {
24765        return function() {
24766          var args = [];
24767          forEach(arguments, function(arg) {
24768            args.push(formatError(arg));
24769          });
24770          return logFn.apply(console, args);
24771        };
24772      }
24773
24774      // we are IE which either doesn't have window.console => this is noop and we do nothing,
24775      // or we are IE where console.log doesn't have apply so we log at least first 2 args
24776      return function(arg1, arg2) {
24777        logFn(arg1, arg2 == null ? '' : arg2);
24778      };
24779    }
24780  }];
24781}
24782
24783/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
24784 *     Any commits to this file should be reviewed with security in mind.  *
24785 *   Changes to this file can potentially create security vulnerabilities. *
24786 *          An approval from 2 Core members with history of modifying      *
24787 *                         this file is required.                          *
24788 *                                                                         *
24789 *  Does the change somehow allow for arbitrary javascript to be executed? *
24790 *    Or allows for someone to change the prototype of built-in objects?   *
24791 *     Or gives undesired access to variables likes document or window?    *
24792 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
24793
24794var $parseMinErr = minErr('$parse');
24795
24796var objectValueOf = {}.constructor.prototype.valueOf;
24797
24798// Sandboxing Angular Expressions
24799// ------------------------------
24800// Angular expressions are no longer sandboxed. So it is now even easier to access arbitrary JS code by
24801// various means such as obtaining a reference to native JS functions like the Function constructor.
24802//
24803// As an example, consider the following Angular
vendor: 17,378 bytes, lines 24803-25404
24803 expression:
24804//
24805//   {}.toString.constructor('alert("evil JS code")')
24806//
24807// It is important to realize that if you create an expression from a string that contains user provided
24808// content then it is possible that your application contains a security vulnerability to an XSS style attack.
24809//
24810// See https://docs.angularjs.org/guide/security
24811
24812
24813function getStringValue(name) {
24814  // Property names must be strings. This means that non-string objects cannot be used
24815  // as keys in an object. Any non-string object, including a number, is typecasted
24816  // into a string via the toString method.
24817  // -- MDN, https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Operators/Property_accessors#Property_names
24818  //
24819  // So, to ensure that we are checking the same `name` that JavaScript would use, we cast it
24820  // to a string. It's not always possible. If `name` is an object and its `toString` method is
24821  // 'broken' (doesn't return a string, isn't a function, etc.), an error will be thrown:
24822  //
24823  // TypeError: Cannot convert object to primitive value
24824  //
24825  // For performance reasons, we don't catch this error here and allow it to propagate up the call
24826  // stack. Note that you'll get the same error in JavaScript if you try to access a property using
24827  // such a 'broken' object as a key.
24828  return name + '';
24829}
24830
24831
24832var OPERATORS = createMap();
24833forEach('+ - * / % === !== == != < > <= >= && || ! = |'.split(' '), function(operator) { OPERATORS[operator] = true; });
24834var ESCAPE = {'n':'\n', 'f':'\f', 'r':'\r', 't':'\t', 'v':'\v', '\'':'\'', '"':'"'};
24835
24836
24837/////////////////////////////////////////
24838
24839
24840/**
24841 * @constructor
24842 */
24843var Lexer = function Lexer(options) {
24844  this.options = options;
24845};
24846
24847Lexer.prototype = {
24848  constructor: Lexer,
24849
24850  lex: function(text) {
24851    this.text = text;
24852    this.index = 0;
24853    this.tokens = [];
24854
24855    while (this.index < this.text.length) {
24856      var ch = this.text.charAt(this.index);
24857      if (ch === '"' || ch === '\'') {
24858        this.readString(ch);
24859      } else if (this.isNumber(ch) || ch === '.' && this.isNumber(this.peek())) {
24860        this.readNumber();
24861      } else if (this.isIdentifierStart(this.peekMultichar())) {
24862        this.readIdent();
24863      } else if (this.is(ch, '(){}[].,;:?')) {
24864        this.tokens.push({index: this.index, text: ch});
24865        this.index++;
24866      } else if (this.isWhitespace(ch)) {
24867        this.index++;
24868      } else {
24869        var ch2 = ch + this.peek();
24870        var ch3 = ch2 + this.peek(2);
24871        var op1 = OPERATORS[ch];
24872        var op2 = OPERATORS[ch2];
24873        var op3 = OPERATORS[ch3];
24874        if (op1 || op2 || op3) {
24875          var token = op3 ? ch3 : (op2 ? ch2 : ch);
24876          this.tokens.push({index: this.index, text: token, operator: true});
24877          this.index += token.length;
24878        } else {
24879          this.throwError('Unexpected next character ', this.index, this.index + 1);
24880        }
24881      }
24882    }
24883    return this.tokens;
24884  },
24885
24886  is: function(ch, chars) {
24887    return chars.indexOf(ch) !== -1;
24888  },
24889
24890  peek: function(i) {
24891    var num = i || 1;
24892    return (this.index + num < this.text.length) ? this.text.charAt(this.index + num) : false;
24893  },
24894
24895  isNumber: function(ch) {
24896    return ('0' <= ch && ch <= '9') && typeof ch === 'string';
24897  },
24898
24899  isWhitespace: function(ch) {
24900    // IE treats non-breaking space as \u00A0
24901    return (ch === ' ' || ch === '\r' || ch === '\t' ||
24902            ch === '\n' || ch === '\v' || ch === '\u00A0');
24903  },
24904
24905  isIdentifierStart: function(ch) {
24906    return this.options.isIdentifierStart ?
24907        this.options.isIdentifierStart(ch, this.codePointAt(ch)) :
24908        this.isValidIdentifierStart(ch);
24909  },
24910
24911  isValidIdentifierStart: function(ch) {
24912    return ('a' <= ch && ch <= 'z' ||
24913            'A' <= ch && ch <= 'Z' ||
24914            '_' === ch || ch === '$');
24915  },
24916
24917  isIdentifierContinue: function(ch) {
24918    return this.options.isIdentifierContinue ?
24919        this.options.isIdentifierContinue(ch, this.codePointAt(ch)) :
24920        this.isValidIdentifierContinue(ch);
24921  },
24922
24923  isValidIdentifierContinue: function(ch, cp) {
24924    return this.isValidIdentifierStart(ch, cp) || this.isNumber(ch);
24925  },
24926
24927  codePointAt: function(ch) {
24928    if (ch.length === 1) return ch.charCodeAt(0);
24929    // eslint-disable-next-line no-bitwise
24930    return (ch.charCodeAt(0) << 10) + ch.charCodeAt(1) - 0x35FDC00;
24931  },
24932
24933  peekMultichar: function() {
24934    var ch = this.text.charAt(this.index);
24935    var peek = this.peek();
24936    if (!peek) {
24937      return ch;
24938    }
24939    var cp1 = ch.charCodeAt(0);
24940    var cp2 = peek.charCodeAt(0);
24941    if (cp1 >= 0xD800 && cp1 <= 0xDBFF && cp2 >= 0xDC00 && cp2 <= 0xDFFF) {
24942      return ch + peek;
24943    }
24944    return ch;
24945  },
24946
24947  isExpOperator: function(ch) {
24948    return (ch === '-' || ch === '+' || this.isNumber(ch));
24949  },
24950
24951  throwError: function(error, start, end) {
24952    end = end || this.index;
24953    var colStr = (isDefined(start)
24954            ? 's ' + start +  '-' + this.index + ' [' + this.text.substring(start, end) + ']'
24955            : ' ' + end);
24956    throw $parseMinErr('lexerr', 'Lexer Error: {0} at column{1} in expression [{2}].',
24957        error, colStr, this.text);
24958  },
24959
24960  readNumber: function() {
24961    var number = '';
24962    var start = this.index;
24963    while (this.index < this.text.length) {
24964      var ch = lowercase(this.text.charAt(this.index));
24965      if (ch === '.' || this.isNumber(ch)) {
24966        number += ch;
24967      } else {
24968        var peekCh = this.peek();
24969        if (ch === 'e' && this.isExpOperator(peekCh)) {
24970          number += ch;
24971        } else if (this.isExpOperator(ch) &&
24972            peekCh && this.isNumber(peekCh) &&
24973            number.charAt(number.length - 1) === 'e') {
24974          number += ch;
24975        } else if (this.isExpOperator(ch) &&
24976            (!peekCh || !this.isNumber(peekCh)) &&
24977            number.charAt(number.length - 1) === 'e') {
24978          this.throwError('Invalid exponent');
24979        } else {
24980          break;
24981        }
24982      }
24983      this.index++;
24984    }
24985    this.tokens.push({
24986      index: start,
24987      text: number,
24988      constant: true,
24989      value: Number(number)
24990    });
24991  },
24992
24993  readIdent: function() {
24994    var start = this.index;
24995    this.index += this.peekMultichar().length;
24996    while (this.index < this.text.length) {
24997      var ch = this.peekMultichar();
24998      if (!this.isIdentifierContinue(ch)) {
24999        break;
25000      }
25001      this.index += ch.length;
25002    }
25003    this.tokens.push({
25004      index: start,
25005      text: this.text.slice(start, this.index),
25006      identifier: true
25007    });
25008  },
25009
25010  readString: function(quote) {
25011    var start = this.index;
25012    this.index++;
25013    var string = '';
25014    var rawString = quote;
25015    var escape = false;
25016    while (this.index < this.text.length) {
25017      var ch = this.text.charAt(this.index);
25018      rawString += ch;
25019      if (escape) {
25020        if (ch === 'u') {
25021          var hex = this.text.substring(this.index + 1, this.index + 5);
25022          if (!hex.match(/[\da-f]{4}/i)) {
25023            this.throwError('Invalid unicode escape [\\u' + hex + ']');
25024          }
25025          this.index += 4;
25026          string += String.fromCharCode(parseInt(hex, 16));
25027        } else {
25028          var rep = ESCAPE[ch];
25029          string = string + (rep || ch);
25030        }
25031        escape = false;
25032      } else if (ch === '\\') {
25033        escape = true;
25034      } else if (ch === quote) {
25035        this.index++;
25036        this.tokens.push({
25037          index: start,
25038          text: rawString,
25039          constant: true,
25040          value: string
25041        });
25042        return;
25043      } else {
25044        string += ch;
25045      }
25046      this.index++;
25047    }
25048    this.throwError('Unterminated quote', start);
25049  }
25050};
25051
25052var AST = function AST(lexer, options) {
25053  this.lexer = lexer;
25054  this.options = options;
25055};
25056
25057AST.Program = 'Program';
25058AST.ExpressionStatement = 'ExpressionStatement';
25059AST.AssignmentExpression = 'AssignmentExpression';
25060AST.ConditionalExpression = 'ConditionalExpression';
25061AST.LogicalExpression = 'LogicalExpression';
25062AST.BinaryExpression = 'BinaryExpression';
25063AST.UnaryExpression = 'UnaryExpression';
25064AST.CallExpression = 'CallExpression';
25065AST.MemberExpression = 'MemberExpression';
25066AST.Identifier = 'Identifier';
25067AST.Literal = 'Literal';
25068AST.ArrayExpression = 'ArrayExpression';
25069AST.Property = 'Property';
25070AST.ObjectExpression = 'ObjectExpression';
25071AST.ThisExpression = 'ThisExpression';
25072AST.LocalsExpression = 'LocalsExpression';
25073
25074// Internal use only
25075AST.NGValueParameter = 'NGValueParameter';
25076
25077AST.prototype = {
25078  ast: function(text) {
25079    this.text = text;
25080    this.tokens = this.lexer.lex(text);
25081
25082    var value = this.program();
25083
25084    if (this.tokens.length !== 0) {
25085      this.throwError('is an unexpected token', this.tokens[0]);
25086    }
25087
25088    return value;
25089  },
25090
25091  program: function() {
25092    var body = [];
25093    while (true) {
25094      if (this.tokens.length > 0 && !this.peek('}', ')', ';', ']'))
25095        body.push(this.expressionStatement());
25096      if (!this.expect(';')) {
25097        return { type: AST.Program, body: body};
25098      }
25099    }
25100  },
25101
25102  expressionStatement: function() {
25103    return { type: AST.ExpressionStatement, expression: this.filterChain() };
25104  },
25105
25106  filterChain: function() {
25107    var left = this.expression();
25108    while (this.expect('|')) {
25109      left = this.filter(left);
25110    }
25111    return left;
25112  },
25113
25114  expression: function() {
25115    return this.assignment();
25116  },
25117
25118  assignment: function() {
25119    var result = this.ternary();
25120    if (this.expect('=')) {
25121      if (!isAssignable(result)) {
25122        throw $parseMinErr('lval', 'Trying to assign a value to a non l-value');
25123      }
25124
25125      result = { type: AST.AssignmentExpression, left: result, right: this.assignment(), operator: '='};
25126    }
25127    return result;
25128  },
25129
25130  ternary: function() {
25131    var test = this.logicalOR();
25132    var alternate;
25133    var consequent;
25134    if (this.expect('?')) {
25135      alternate = this.expression();
25136      if (this.consume(':')) {
25137        consequent = this.expression();
25138        return { type: AST.ConditionalExpression, test: test, alternate: alternate, consequent: consequent};
25139      }
25140    }
25141    return test;
25142  },
25143
25144  logicalOR: function() {
25145    var left = this.logicalAND();
25146    while (this.expect('||')) {
25147      left = { type: AST.LogicalExpression, operator: '||', left: left, right: this.logicalAND() };
25148    }
25149    return left;
25150  },
25151
25152  logicalAND: function() {
25153    var left = this.equality();
25154    while (this.expect('&&')) {
25155      left = { type: AST.LogicalExpression, operator: '&&', left: left, right: this.equality()};
25156    }
25157    return left;
25158  },
25159
25160  equality: function() {
25161    var left = this.relational();
25162    var token;
25163    while ((token = this.expect('==','!=','===','!=='))) {
25164      left = { type: AST.BinaryExpression, operator: token.text, left: left, right: this.relational() };
25165    }
25166    return left;
25167  },
25168
25169  relational: function() {
25170    var left = this.additive();
25171    var token;
25172    while ((token = this.expect('<', '>', '<=', '>='))) {
25173      left = { type: AST.BinaryExpression, operator: token.text, left: left, right: this.additive() };
25174    }
25175    return left;
25176  },
25177
25178  additive: function() {
25179    var left = this.multiplicative();
25180    var token;
25181    while ((token = this.expect('+','-'))) {
25182      left = { type: AST.BinaryExpression, operator: token.text, left: left, right: this.multiplicative() };
25183    }
25184    return left;
25185  },
25186
25187  multiplicative: function() {
25188    var left = this.unary();
25189    var token;
25190    while ((token = this.expect('*','/','%'))) {
25191      left = { type: AST.BinaryExpression, operator: token.text, left: left, right: this.unary() };
25192    }
25193    return left;
25194  },
25195
25196  unary: function() {
25197    var token;
25198    if ((token = this.expect('+', '-', '!'))) {
25199      return { type: AST.UnaryExpression, operator: token.text, prefix: true, argument: this.unary() };
25200    } else {
25201      return this.primary();
25202    }
25203  },
25204
25205  primary: function() {
25206    var primary;
25207    if (this.expect('(')) {
25208      primary = this.filterChain();
25209      this.consume(')');
25210    } else if (this.expect('[')) {
25211      primary = this.arrayDeclaration();
25212    } else if (this.expect('{')) {
25213      primary = this.object();
25214    } else if (this.selfReferential.hasOwnProperty(this.peek().text)) {
25215      primary = copy(this.selfReferential[this.consume().text]);
25216    } else if (this.options.literals.hasOwnProperty(this.peek().text)) {
25217      primary = { type: AST.Literal, value: this.options.literals[this.consume().text]};
25218    } else if (this.peek().identifier) {
25219      primary = this.identifier();
25220    } else if (this.peek().constant) {
25221      primary = this.constant();
25222    } else {
25223      this.throwError('not a primary expression', this.peek());
25224    }
25225
25226    var next;
25227    while ((next = this.expect('(', '[', '.'))) {
25228      if (next.text === '(') {
25229        primary = {type: AST.CallExpression, callee: primary, arguments: this.parseArguments() };
25230        this.consume(')');
25231      } else if (next.text === '[') {
25232        primary = { type: AST.MemberExpression, object: primary, property: this.expression(), computed: true };
25233        this.consume(']');
25234      } else if (next.text === '.') {
25235        primary = { type: AST.MemberExpression, object: primary, property: this.identifier(), computed: false };
25236      } else {
25237        this.throwError('IMPOSSIBLE');
25238      }
25239    }
25240    return primary;
25241  },
25242
25243  filter: function(baseExpression) {
25244    var args = [baseExpression];
25245    var result = {type: AST.CallExpression, callee: this.identifier(), arguments: args, filter: true};
25246
25247    while (this.expect(':')) {
25248      args.push(this.expression());
25249    }
25250
25251    return result;
25252  },
25253
25254  parseArguments: function() {
25255    var args = [];
25256    if (this.peekToken().text !== ')') {
25257      do {
25258        args.push(this.filterChain());
25259      } while (this.expect(','));
25260    }
25261    return args;
25262  },
25263
25264  identifier: function() {
25265    var token = this.consume();
25266    if (!token.identifier) {
25267      this.throwError('is not a valid identifier', token);
25268    }
25269    return { type: AST.Identifier, name: token.text };
25270  },
25271
25272  constant: function() {
25273    // TODO check that it is a constant
25274    return { type: AST.Literal, value: this.consume().value };
25275  },
25276
25277  arrayDeclaration: function() {
25278    var elements = [];
25279    if (this.peekToken().text !== ']') {
25280      do {
25281        if (this.peek(']')) {
25282          // Support trailing commas per ES5.1.
25283          break;
25284        }
25285        elements.push(this.expression());
25286      } while (this.expect(','));
25287    }
25288    this.consume(']');
25289
25290    return { type: AST.ArrayExpression, elements: elements };
25291  },
25292
25293  object: function() {
25294    var properties = [], property;
25295    if (this.peekToken().text !== '}') {
25296      do {
25297        if (this.peek('}')) {
25298          // Support trailing commas per ES5.1.
25299          break;
25300        }
25301        property = {type: AST.Property, kind: 'init'};
25302        if (this.peek().constant) {
25303          property.key = this.constant();
25304          property.computed = false;
25305          this.consume(':');
25306          property.value = this.expression();
25307        } else if (this.peek().identifier) {
25308          property.key = this.identifier();
25309          property.computed = false;
25310          if (this.peek(':')) {
25311            this.consume(':');
25312            property.value = this.expression();
25313          } else {
25314            property.value = property.key;
25315          }
25316        } else if (this.peek('[')) {
25317          this.consume('[');
25318          property.key = this.expression();
25319          this.consume(']');
25320          property.computed = true;
25321          this.consume(':');
25322          property.value = this.expression();
25323        } else {
25324          this.throwError('invalid key', this.peek());
25325        }
25326        properties.push(property);
25327      } while (this.expect(','));
25328    }
25329    this.consume('}');
25330
25331    return {type: AST.ObjectExpression, properties: properties };
25332  },
25333
25334  throwError: function(msg, token) {
25335    throw $parseMinErr('syntax',
25336        'Syntax Error: Token \'{0}\' {1} at column {2} of the expression [{3}] starting at [{4}].',
25337          token.text, msg, (token.index + 1), this.text, this.text.substring(token.index));
25338  },
25339
25340  consume: function(e1) {
25341    if (this.tokens.length === 0) {
25342      throw $parseMinErr('ueoe', 'Unexpected end of expression: {0}', this.text);
25343    }
25344
25345    var token = this.expect(e1);
25346    if (!token) {
25347      this.throwError('is unexpected, expecting [' + e1 + ']', this.peek());
25348    }
25349    return token;
25350  },
25351
25352  peekToken: function() {
25353    if (this.tokens.length === 0) {
25354      throw $parseMinErr('ueoe', 'Unexpected end of expression: {0}', this.text);
25355    }
25356    return this.tokens[0];
25357  },
25358
25359  peek: function(e1, e2, e3, e4) {
25360    return this.peekAhead(0, e1, e2, e3, e4);
25361  },
25362
25363  peekAhead: function(i, e1, e2, e3, e4) {
25364    if (this.tokens.length > i) {
25365      var token = this.tokens[i];
25366      var t = token.text;
25367      if (t === e1 || t === e2 || t === e3 || t === e4 ||
25368          (!e1 && !e2 && !e3 && !e4)) {
25369        return token;
25370      }
25371    }
25372    return false;
25373  },
25374
25375  expect: function(e1, e2, e3, e4) {
25376    var token = this.peek(e1, e2, e3, e4);
25377    if (token) {
25378      this.tokens.shift();
25379      return token;
25380    }
25381    return false;
25382  },
25383
25384  selfReferential: {
25385    'this': {type: AST.ThisExpression },
25386    '$locals': {type: AST.LocalsExpression }
25387  }
25388};
25389
25390function ifDefined(v, d) {
25391  return typeof v !== 'undefined' ? v : d;
25392}
25393
25394function plusFn(l, r) {
25395  if (typeof l === 'undefined') return r;
25396  if (typeof r === 'undefined') return l;
25397  return l + r;
25398}
25399
25400function isStateless($filter, filterName) {
25401  var fn = $filter(filterName);
25402  return !fn.$stateful;
25403}
25404
vendor: 7,330 bytes, lines 25405-25632
25405function findConstantAndWatchExpressions(ast, $filter) {
25406  var allConstants;
25407  var argsToWatch;
25408  var isStatelessFilter;
25409  switch (ast.type) {
25410  case AST.Program:
25411    allConstants = true;
25412    forEach(ast.body, function(expr) {
25413      findConstantAndWatchExpressions(expr.expression, $filter);
25414      allConstants = allConstants && expr.expression.constant;
25415    });
25416    ast.constant = allConstants;
25417    break;
25418  case AST.Literal:
25419    ast.constant = true;
25420    ast.toWatch = [];
25421    break;
25422  case AST.UnaryExpression:
25423    findConstantAndWatchExpressions(ast.argument, $filter);
25424    ast.constant = ast.argument.constant;
25425    ast.toWatch = ast.argument.toWatch;
25426    break;
25427  case AST.BinaryExpression:
25428    findConstantAndWatchExpressions(ast.left, $filter);
25429    findConstantAndWatchExpressions(ast.right, $filter);
25430    ast.constant = ast.left.constant && ast.right.constant;
25431    ast.toWatch = ast.left.toWatch.concat(ast.right.toWatch);
25432    break;
25433  case AST.LogicalExpression:
25434    findConstantAndWatchExpressions(ast.left, $filter);
25435    findConstantAndWatchExpressions(ast.right, $filter);
25436    ast.constant = ast.left.constant && ast.right.constant;
25437    ast.toWatch = ast.constant ? [] : [ast];
25438    break;
25439  case AST.ConditionalExpression:
25440    findConstantAndWatchExpressions(ast.test, $filter);
25441    findConstantAndWatchExpressions(ast.alternate, $filter);
25442    findConstantAndWatchExpressions(ast.consequent, $filter);
25443    ast.constant = ast.test.constant && ast.alternate.constant && ast.consequent.constant;
25444    ast.toWatch = ast.constant ? [] : [ast];
25445    break;
25446  case AST.Identifier:
25447    ast.constant = false;
25448    ast.toWatch = [ast];
25449    break;
25450  case AST.MemberExpression:
25451    findConstantAndWatchExpressions(ast.object, $filter);
25452    if (ast.computed) {
25453      findConstantAndWatchExpressions(ast.property, $filter);
25454    }
25455    ast.constant = ast.object.constant && (!ast.computed || ast.property.constant);
25456    ast.toWatch = [ast];
25457    break;
25458  case AST.CallExpression:
25459    isStatelessFilter = ast.filter ? isStateless($filter, ast.callee.name) : false;
25460    allConstants = isStatelessFilter;
25461    argsToWatch = [];
25462    forEach(ast.arguments, function(expr) {
25463      findConstantAndWatchExpressions(expr, $filter);
25464      allConstants = allConstants && expr.constant;
25465      if (!expr.constant) {
25466        argsToWatch.push.apply(argsToWatch, expr.toWatch);
25467      }
25468    });
25469    ast.constant = allConstants;
25470    ast.toWatch = isStatelessFilter ? argsToWatch : [ast];
25471    break;
25472  case AST.AssignmentExpression:
25473    findConstantAndWatchExpressions(ast.left, $filter);
25474    findConstantAndWatchExpressions(ast.right, $filter);
25475    ast.constant = ast.left.constant && ast.right.constant;
25476    ast.toWatch = [ast];
25477    break;
25478  case AST.ArrayExpression:
25479    allConstants = true;
25480    argsToWatch = [];
25481    forEach(ast.elements, function(expr) {
25482      findConstantAndWatchExpressions(expr, $filter);
25483      allConstants = allConstants && expr.constant;
25484      if (!expr.constant) {
25485        argsToWatch.push.apply(argsToWatch, expr.toWatch);
25486      }
25487    });
25488    ast.constant = allConstants;
25489    ast.toWatch = argsToWatch;
25490    break;
25491  case AST.ObjectExpression:
25492    allConstants = true;
25493    argsToWatch = [];
25494    forEach(ast.properties, function(property) {
25495      findConstantAndWatchExpressions(property.value, $filter);
25496      allConstants = allConstants && property.value.constant && !property.computed;
25497      if (!property.value.constant) {
25498        argsToWatch.push.apply(argsToWatch, property.value.toWatch);
25499      }
25500      if (property.computed) {
25501        findConstantAndWatchExpressions(property.key, $filter);
25502        if (!property.key.constant) {
25503          argsToWatch.push.apply(argsToWatch, property.key.toWatch);
25504        }
25505      }
25506
25507    });
25508    ast.constant = allConstants;
25509    ast.toWatch = argsToWatch;
25510    break;
25511  case AST.ThisExpression:
25512    ast.constant = false;
25513    ast.toWatch = [];
25514    break;
25515  case AST.LocalsExpression:
25516    ast.constant = false;
25517    ast.toWatch = [];
25518    break;
25519  }
25520}
25521
25522function getInputs(body) {
25523  if (body.length !== 1) return;
25524  var lastExpression = body[0].expression;
25525  var candidate = lastExpression.toWatch;
25526  if (candidate.length !== 1) return candidate;
25527  return candidate[0] !== lastExpression ? candidate : undefined;
25528}
25529
25530function isAssignable(ast) {
25531  return ast.type === AST.Identifier || ast.type === AST.MemberExpression;
25532}
25533
25534function assignableAST(ast) {
25535  if (ast.body.length === 1 && isAssignable(ast.body[0].expression)) {
25536    return {type: AST.AssignmentExpression, left: ast.body[0].expression, right: {type: AST.NGValueParameter}, operator: '='};
25537  }
25538}
25539
25540function isLiteral(ast) {
25541  return ast.body.length === 0 ||
25542      ast.body.length === 1 && (
25543      ast.body[0].expression.type === AST.Literal ||
25544      ast.body[0].expression.type === AST.ArrayExpression ||
25545      ast.body[0].expression.type === AST.ObjectExpression);
25546}
25547
25548function isConstant(ast) {
25549  return ast.constant;
25550}
25551
25552function ASTCompiler(astBuilder, $filter) {
25553  this.astBuilder = astBuilder;
25554  this.$filter = $filter;
25555}
25556
25557ASTCompiler.prototype = {
25558  compile: function(expression) {
25559    var self = this;
25560    var ast = this.astBuilder.ast(expression);
25561    this.state = {
25562      nextId: 0,
25563      filters: {},
25564      fn: {vars: [], body: [], own: {}},
25565      assign: {vars: [], body: [], own: {}},
25566      inputs: []
25567    };
25568    findConstantAndWatchExpressions(ast, self.$filter);
25569    var extra = '';
25570    var assignable;
25571    this.stage = 'assign';
25572    if ((assignable = assignableAST(ast))) {
25573      this.state.computing = 'assign';
25574      var result = this.nextId();
25575      this.recurse(assignable, result);
25576      this.return_(result);
25577      extra = 'fn.assign=' + this.generateFunction('assign', 's,v,l');
25578    }
25579    var toWatch = getInputs(ast.body);
25580    self.stage = 'inputs';
25581    forEach(toWatch, function(watch, key) {
25582      var fnKey = 'fn' + key;
25583      self.state[fnKey] = {vars: [], body: [], own: {}};
25584      self.state.computing = fnKey;
25585      var intoId = self.nextId();
25586      self.recurse(watch, intoId);
25587      self.return_(intoId);
25588      self.state.inputs.push(fnKey);
25589      watch.watchId = key;
25590    });
25591    this.state.computing = 'fn';
25592    this.stage = 'main';
25593    this.recurse(ast);
25594    var fnString =
25595      // The build and minification steps remove the string "use strict" from the code, but this is done using a regex.
25596      // This is a workaround for this until we do a better job at only removing the prefix only when we should.
25597      '"' + this.USE + ' ' + this.STRICT + '";\n' +
25598      this.filterPrefix() +
25599      'var fn=' + this.generateFunction('fn', 's,l,a,i') +
25600      extra +
25601      this.watchFns() +
25602      'return fn;';
25603
25604    // eslint-disable-next-line no-new-func
25605    var fn = (new Function('$filter',
25606        'getStringValue',
25607        'ifDefined',
25608        'plus',
25609        fnString))(
25610          this.$filter,
25611          getStringValue,
25612          ifDefined,
25613          plusFn);
25614    this.state = this.stage = undefined;
25615    fn.literal = isLiteral(ast);
25616    fn.constant = isConstant(ast);
25617    return fn;
25618  },
25619
25620  USE: 'use',
25621
25622  STRICT: 'strict',
25623
25624  watchFns: function() {
25625    var result = [];
25626    var fns = this.state.inputs;
25627    var self = this;
25628    forEach(fns, function(name) {
25629      result.push('var ' + name + '=' + self.generateFunction(name, 's'));
25630    });
25631    if (fns.length) {
25632      result.push('fn.inputs=[' + fns
vendor: 12,657 bytes, lines 25632-26019
25632.join(',') + '];');
25633    }
25634    return result.join('');
25635  },
25636
25637  generateFunction: function(name, params) {
25638    return 'function(' + params + '){' +
25639        this.varsPrefix(name) +
25640        this.body(name) +
25641        '};';
25642  },
25643
25644  filterPrefix: function() {
25645    var parts = [];
25646    var self = this;
25647    forEach(this.state.filters, function(id, filter) {
25648      parts.push(id + '=$filter(' + self.escape(filter) + ')');
25649    });
25650    if (parts.length) return 'var ' + parts.join(',') + ';';
25651    return '';
25652  },
25653
25654  varsPrefix: function(section) {
25655    return this.state[section].vars.length ? 'var ' + this.state[section].vars.join(',') + ';' : '';
25656  },
25657
25658  body: function(section) {
25659    return this.state[section].body.join('');
25660  },
25661
25662  recurse: function(ast, intoId, nameId, recursionFn, create, skipWatchIdCheck) {
25663    var left, right, self = this, args, expression, computed;
25664    recursionFn = recursionFn || noop;
25665    if (!skipWatchIdCheck && isDefined(ast.watchId)) {
25666      intoId = intoId || this.nextId();
25667      this.if_('i',
25668        this.lazyAssign(intoId, this.computedMember('i', ast.watchId)),
25669        this.lazyRecurse(ast, intoId, nameId, recursionFn, create, true)
25670      );
25671      return;
25672    }
25673    switch (ast.type) {
25674    case AST.Program:
25675      forEach(ast.body, function(expression, pos) {
25676        self.recurse(expression.expression, undefined, undefined, function(expr) { right = expr; });
25677        if (pos !== ast.body.length - 1) {
25678          self.current().body.push(right, ';');
25679        } else {
25680          self.return_(right);
25681        }
25682      });
25683      break;
25684    case AST.Literal:
25685      expression = this.escape(ast.value);
25686      this.assign(intoId, expression);
25687      recursionFn(intoId || expression);
25688      break;
25689    case AST.UnaryExpression:
25690      this.recurse(ast.argument, undefined, undefined, function(expr) { right = expr; });
25691      expression = ast.operator + '(' + this.ifDefined(right, 0) + ')';
25692      this.assign(intoId, expression);
25693      recursionFn(expression);
25694      break;
25695    case AST.BinaryExpression:
25696      this.recurse(ast.left, undefined, undefined, function(expr) { left = expr; });
25697      this.recurse(ast.right, undefined, undefined, function(expr) { right = expr; });
25698      if (ast.operator === '+') {
25699        expression = this.plus(left, right);
25700      } else if (ast.operator === '-') {
25701        expression = this.ifDefined(left, 0) + ast.operator + this.ifDefined(right, 0);
25702      } else {
25703        expression = '(' + left + ')' + ast.operator + '(' + right + ')';
25704      }
25705      this.assign(intoId, expression);
25706      recursionFn(expression);
25707      break;
25708    case AST.LogicalExpression:
25709      intoId = intoId || this.nextId();
25710      self.recurse(ast.left, intoId);
25711      self.if_(ast.operator === '&&' ? intoId : self.not(intoId), self.lazyRecurse(ast.right, intoId));
25712      recursionFn(intoId);
25713      break;
25714    case AST.ConditionalExpression:
25715      intoId = intoId || this.nextId();
25716      self.recurse(ast.test, intoId);
25717      self.if_(intoId, self.lazyRecurse(ast.alternate, intoId), self.lazyRecurse(ast.consequent, intoId));
25718      recursionFn(intoId);
25719      break;
25720    case AST.Identifier:
25721      intoId = intoId || this.nextId();
25722      if (nameId) {
25723        nameId.context = self.stage === 'inputs' ? 's' : this.assign(this.nextId(), this.getHasOwnProperty('l', ast.name) + '?l:s');
25724        nameId.computed = false;
25725        nameId.name = ast.name;
25726      }
25727      self.if_(self.stage === 'inputs' || self.not(self.getHasOwnProperty('l', ast.name)),
25728        function() {
25729          self.if_(self.stage === 'inputs' || 's', function() {
25730            if (create && create !== 1) {
25731              self.if_(
25732                self.isNull(self.nonComputedMember('s', ast.name)),
25733                self.lazyAssign(self.nonComputedMember('s', ast.name), '{}'));
25734            }
25735            self.assign(intoId, self.nonComputedMember('s', ast.name));
25736          });
25737        }, intoId && self.lazyAssign(intoId, self.nonComputedMember('l', ast.name))
25738        );
25739      recursionFn(intoId);
25740      break;
25741    case AST.MemberExpression:
25742      left = nameId && (nameId.context = this.nextId()) || this.nextId();
25743      intoId = intoId || this.nextId();
25744      self.recurse(ast.object, left, undefined, function() {
25745        self.if_(self.notNull(left), function() {
25746          if (ast.computed) {
25747            right = self.nextId();
25748            self.recurse(ast.property, right);
25749            self.getStringValue(right);
25750            if (create && create !== 1) {
25751              self.if_(self.not(self.computedMember(left, right)), self.lazyAssign(self.computedMember(left, right), '{}'));
25752            }
25753            expression = self.computedMember(left, right);
25754            self.assign(intoId, expression);
25755            if (nameId) {
25756              nameId.computed = true;
25757              nameId.name = right;
25758            }
25759          } else {
25760            if (create && create !== 1) {
25761              self.if_(self.isNull(self.nonComputedMember(left, ast.property.name)), self.lazyAssign(self.nonComputedMember(left, ast.property.name), '{}'));
25762            }
25763            expression = self.nonComputedMember(left, ast.property.name);
25764            self.assign(intoId, expression);
25765            if (nameId) {
25766              nameId.computed = false;
25767              nameId.name = ast.property.name;
25768            }
25769          }
25770        }, function() {
25771          self.assign(intoId, 'undefined');
25772        });
25773        recursionFn(intoId);
25774      }, !!create);
25775      break;
25776    case AST.CallExpression:
25777      intoId = intoId || this.nextId();
25778      if (ast.filter) {
25779        right = self.filter(ast.callee.name);
25780        args = [];
25781        forEach(ast.arguments, function(expr) {
25782          var argument = self.nextId();
25783          self.recurse(expr, argument);
25784          args.push(argument);
25785        });
25786        expression = right + '(' + args.join(',') + ')';
25787        self.assign(intoId, expression);
25788        recursionFn(intoId);
25789      } else {
25790        right = self.nextId();
25791        left = {};
25792        args = [];
25793        self.recurse(ast.callee, right, left, function() {
25794          self.if_(self.notNull(right), function() {
25795            forEach(ast.arguments, function(expr) {
25796              self.recurse(expr, ast.constant ? undefined : self.nextId(), undefined, function(argument) {
25797                args.push(argument);
25798              });
25799            });
25800            if (left.name) {
25801              expression = self.member(left.context, left.name, left.computed) + '(' + args.join(',') + ')';
25802            } else {
25803              expression = right + '(' + args.join(',') + ')';
25804            }
25805            self.assign(intoId, expression);
25806          }, function() {
25807            self.assign(intoId, 'undefined');
25808          });
25809          recursionFn(intoId);
25810        });
25811      }
25812      break;
25813    case AST.AssignmentExpression:
25814      right = this.nextId();
25815      left = {};
25816      this.recurse(ast.left, undefined, left, function() {
25817        self.if_(self.notNull(left.context), function() {
25818          self.recurse(ast.right, right);
25819          expression = self.member(left.context, left.name, left.computed) + ast.operator + right;
25820          self.assign(intoId, expression);
25821          recursionFn(intoId || expression);
25822        });
25823      }, 1);
25824      break;
25825    case AST.ArrayExpression:
25826      args = [];
25827      forEach(ast.elements, function(expr) {
25828        self.recurse(expr, ast.constant ? undefined : self.nextId(), undefined, function(argument) {
25829          args.push(argument);
25830        });
25831      });
25832      expression = '[' + args.join(',') + ']';
25833      this.assign(intoId, expression);
25834      recursionFn(intoId || expression);
25835      break;
25836    case AST.ObjectExpression:
25837      args = [];
25838      computed = false;
25839      forEach(ast.properties, function(property) {
25840        if (property.computed) {
25841          computed = true;
25842        }
25843      });
25844      if (computed) {
25845        intoId = intoId || this.nextId();
25846        this.assign(intoId, '{}');
25847        forEach(ast.properties, function(property) {
25848          if (property.computed) {
25849            left = self.nextId();
25850            self.recurse(property.key, left);
25851          } else {
25852            left = property.key.type === AST.Identifier ?
25853                       property.key.name :
25854                       ('' + property.key.value);
25855          }
25856          right = self.nextId();
25857          self.recurse(property.value, right);
25858          self.assign(self.member(intoId, left, property.computed), right);
25859        });
25860      } else {
25861        forEach(ast.properties, function(property) {
25862          self.recurse(property.value, ast.constant ? undefined : self.nextId(), undefined, function(expr) {
25863            args.push(self.escape(
25864                property.key.type === AST.Identifier ? property.key.name :
25865                  ('' + property.key.value)) +
25866                ':' + expr);
25867          });
25868        });
25869        expression = '{' + args.join(',') + '}';
25870        this.assign(intoId, expression);
25871      }
25872      recursionFn(intoId || expression);
25873      break;
25874    case AST.ThisExpression:
25875      this.assign(intoId, 's');
25876      recursionFn(intoId || 's');
25877      break;
25878    case AST.LocalsExpression:
25879      this.assign(intoId, 'l');
25880      recursionFn(intoId || 'l');
25881      break;
25882    case AST.NGValueParameter:
25883      this.assign(intoId, 'v');
25884      recursionFn(intoId || 'v');
25885      break;
25886    }
25887  },
25888
25889  getHasOwnProperty: function(element, property) {
25890    var key = element + '.' + property;
25891    var own = this.current().own;
25892    if (!own.hasOwnProperty(key)) {
25893      own[key] = this.nextId(false, element + '&&(' + this.escape(property) + ' in ' + element + ')');
25894    }
25895    return own[key];
25896  },
25897
25898  assign: function(id, value) {
25899    if (!id) return;
25900    this.current().body.push(id, '=', value, ';');
25901    return id;
25902  },
25903
25904  filter: function(filterName) {
25905    if (!this.state.filters.hasOwnProperty(filterName)) {
25906      this.state.filters[filterName] = this.nextId(true);
25907    }
25908    return this.state.filters[filterName];
25909  },
25910
25911  ifDefined: function(id, defaultValue) {
25912    return 'ifDefined(' + id + ',' + this.escape(defaultValue) + ')';
25913  },
25914
25915  plus: function(left, right) {
25916    return 'plus(' + left + ',' + right + ')';
25917  },
25918
25919  return_: function(id) {
25920    this.current().body.push('return ', id, ';');
25921  },
25922
25923  if_: function(test, alternate, consequent) {
25924    if (test === true) {
25925      alternate();
25926    } else {
25927      var body = this.current().body;
25928      body.push('if(', test, '){');
25929      alternate();
25930      body.push('}');
25931      if (consequent) {
25932        body.push('else{');
25933        consequent();
25934        body.push('}');
25935      }
25936    }
25937  },
25938
25939  not: function(expression) {
25940    return '!(' + expression + ')';
25941  },
25942
25943  isNull: function(expression) {
25944    return expression + '==null';
25945  },
25946
25947  notNull: function(expression) {
25948    return expression + '!=null';
25949  },
25950
25951  nonComputedMember: function(left, right) {
25952    var SAFE_IDENTIFIER = /^[$_a-zA-Z][$_a-zA-Z0-9]*$/;
25953    var UNSAFE_CHARACTERS = /[^$_a-zA-Z0-9]/g;
25954    if (SAFE_IDENTIFIER.test(right)) {
25955      return left + '.' + right;
25956    } else {
25957      return left  + '["' + right.replace(UNSAFE_CHARACTERS, this.stringEscapeFn) + '"]';
25958    }
25959  },
25960
25961  computedMember: function(left, right) {
25962    return left + '[' + right + ']';
25963  },
25964
25965  member: function(left, right, computed) {
25966    if (computed) return this.computedMember(left, right);
25967    return this.nonComputedMember(left, right);
25968  },
25969
25970  getStringValue: function(item) {
25971    this.assign(item, 'getStringValue(' + item + ')');
25972  },
25973
25974  lazyRecurse: function(ast, intoId, nameId, recursionFn, create, skipWatchIdCheck) {
25975    var self = this;
25976    return function() {
25977      self.recurse(ast, intoId, nameId, recursionFn, create, skipWatchIdCheck);
25978    };
25979  },
25980
25981  lazyAssign: function(id, value) {
25982    var self = this;
25983    return function() {
25984      self.assign(id, value);
25985    };
25986  },
25987
25988  stringEscapeRegex: /[^ a-zA-Z0-9]/g,
25989
25990  stringEscapeFn: function(c) {
25991    return '\\u' + ('0000' + c.charCodeAt(0).toString(16)).slice(-4);
25992  },
25993
25994  escape: function(value) {
25995    if (isString(value)) return '\'' + value.replace(this.stringEscapeRegex, this.stringEscapeFn) + '\'';
25996    if (isNumber(value)) return value.toString();
25997    if (value === true) return 'true';
25998    if (value === false) return 'false';
25999    if (value === null) return 'null';
26000    if (typeof value === 'undefined') return 'undefined';
26001
26002    throw $parseMinErr('esc', 'IMPOSSIBLE');
26003  },
26004
26005  nextId: function(skip, init) {
26006    var id = 'v' + (this.state.nextId++);
26007    if (!skip) {
26008      this.current().vars.push(id + (init ? '=' + init : ''));
26009    }
26010    return id;
26011  },
26012
26013  current: function() {
26014    return this.state[this.state.computing];
26015  }
26016};
26017
26018
26019function ASTInterpreter(
vendor: 1,403 bytes, lines 26019-26067
26019astBuilder, $filter) {
26020  this.astBuilder = astBuilder;
26021  this.$filter = $filter;
26022}
26023
26024ASTInterpreter.prototype = {
26025  compile: function(expression) {
26026    var self = this;
26027    var ast = this.astBuilder.ast(expression);
26028    findConstantAndWatchExpressions(ast, self.$filter);
26029    var assignable;
26030    var assign;
26031    if ((assignable = assignableAST(ast))) {
26032      assign = this.recurse(assignable);
26033    }
26034    var toWatch = getInputs(ast.body);
26035    var inputs;
26036    if (toWatch) {
26037      inputs = [];
26038      forEach(toWatch, function(watch, key) {
26039        var input = self.recurse(watch);
26040        watch.input = input;
26041        inputs.push(input);
26042        watch.watchId = key;
26043      });
26044    }
26045    var expressions = [];
26046    forEach(ast.body, function(expression) {
26047      expressions.push(self.recurse(expression.expression));
26048    });
26049    var fn = ast.body.length === 0 ? noop :
26050             ast.body.length === 1 ? expressions[0] :
26051             function(scope, locals) {
26052               var lastValue;
26053               forEach(expressions, function(exp) {
26054                 lastValue = exp(scope, locals);
26055               });
26056               return lastValue;
26057             };
26058    if (assign) {
26059      fn.assign = function(scope, value, locals) {
26060        return assign(scope, locals, value);
26061      };
26062    }
26063    if (inputs) {
26064      fn.inputs = inputs;
26065    }
26066    fn.literal = isLiteral(ast);
26067    fn.constant = isConstant(ast);
vendor: 11,669 bytes, lines 26067-26395
26067
26068    return fn;
26069  },
26070
26071  recurse: function(ast, context, create) {
26072    var left, right, self = this, args;
26073    if (ast.input) {
26074      return this.inputs(ast.input, ast.watchId);
26075    }
26076    switch (ast.type) {
26077    case AST.Literal:
26078      return this.value(ast.value, context);
26079    case AST.UnaryExpression:
26080      right = this.recurse(ast.argument);
26081      return this['unary' + ast.operator](right, context);
26082    case AST.BinaryExpression:
26083      left = this.recurse(ast.left);
26084      right = this.recurse(ast.right);
26085      return this['binary' + ast.operator](left, right, context);
26086    case AST.LogicalExpression:
26087      left = this.recurse(ast.left);
26088      right = this.recurse(ast.right);
26089      return this['binary' + ast.operator](left, right, context);
26090    case AST.ConditionalExpression:
26091      return this['ternary?:'](
26092        this.recurse(ast.test),
26093        this.recurse(ast.alternate),
26094        this.recurse(ast.consequent),
26095        context
26096      );
26097    case AST.Identifier:
26098      return self.identifier(ast.name, context, create);
26099    case AST.MemberExpression:
26100      left = this.recurse(ast.object, false, !!create);
26101      if (!ast.computed) {
26102        right = ast.property.name;
26103      }
26104      if (ast.computed) right = this.recurse(ast.property);
26105      return ast.computed ?
26106        this.computedMember(left, right, context, create) :
26107        this.nonComputedMember(left, right, context, create);
26108    case AST.CallExpression:
26109      args = [];
26110      forEach(ast.arguments, function(expr) {
26111        args.push(self.recurse(expr));
26112      });
26113      if (ast.filter) right = this.$filter(ast.callee.name);
26114      if (!ast.filter) right = this.recurse(ast.callee, true);
26115      return ast.filter ?
26116        function(scope, locals, assign, inputs) {
26117          var values = [];
26118          for (var i = 0; i < args.length; ++i) {
26119            values.push(args[i](scope, locals, assign, inputs));
26120          }
26121          var value = right.apply(undefined, values, inputs);
26122          return context ? {context: undefined, name: undefined, value: value} : value;
26123        } :
26124        function(scope, locals, assign, inputs) {
26125          var rhs = right(scope, locals, assign, inputs);
26126          var value;
26127          if (rhs.value != null) {
26128            var values = [];
26129            for (var i = 0; i < args.length; ++i) {
26130              values.push(args[i](scope, locals, assign, inputs));
26131            }
26132            value = rhs.value.apply(rhs.context, values);
26133          }
26134          return context ? {value: value} : value;
26135        };
26136    case AST.AssignmentExpression:
26137      left = this.recurse(ast.left, true, 1);
26138      right = this.recurse(ast.right);
26139      return function(scope, locals, assign, inputs) {
26140        var lhs = left(scope, locals, assign, inputs);
26141        var rhs = right(scope, locals, assign, inputs);
26142        lhs.context[lhs.name] = rhs;
26143        return context ? {value: rhs} : rhs;
26144      };
26145    case AST.ArrayExpression:
26146      args = [];
26147      forEach(ast.elements, function(expr) {
26148        args.push(self.recurse(expr));
26149      });
26150      return function(scope, locals, assign, inputs) {
26151        var value = [];
26152        for (var i = 0; i < args.length; ++i) {
26153          value.push(args[i](scope, locals, assign, inputs));
26154        }
26155        return context ? {value: value} : value;
26156      };
26157    case AST.ObjectExpression:
26158      args = [];
26159      forEach(ast.properties, function(property) {
26160        if (property.computed) {
26161          args.push({key: self.recurse(property.key),
26162                     computed: true,
26163                     value: self.recurse(property.value)
26164          });
26165        } else {
26166          args.push({key: property.key.type === AST.Identifier ?
26167                          property.key.name :
26168                          ('' + property.key.value),
26169                     computed: false,
26170                     value: self.recurse(property.value)
26171          });
26172        }
26173      });
26174      return function(scope, locals, assign, inputs) {
26175        var value = {};
26176        for (var i = 0; i < args.length; ++i) {
26177          if (args[i].computed) {
26178            value[args[i].key(scope, locals, assign, inputs)] = args[i].value(scope, locals, assign, inputs);
26179          } else {
26180            value[args[i].key] = args[i].value(scope, locals, assign, inputs);
26181          }
26182        }
26183        return context ? {value: value} : value;
26184      };
26185    case AST.ThisExpression:
26186      return function(scope) {
26187        return context ? {value: scope} : scope;
26188      };
26189    case AST.LocalsExpression:
26190      return function(scope, locals) {
26191        return context ? {value: locals} : locals;
26192      };
26193    case AST.NGValueParameter:
26194      return function(scope, locals, assign) {
26195        return context ? {value: assign} : assign;
26196      };
26197    }
26198  },
26199
26200  'unary+': function(argument, context) {
26201    return function(scope, locals, assign, inputs) {
26202      var arg = argument(scope, locals, assign, inputs);
26203      if (isDefined(arg)) {
26204        arg = +arg;
26205      } else {
26206        arg = 0;
26207      }
26208      return context ? {value: arg} : arg;
26209    };
26210  },
26211  'unary-': function(argument, context) {
26212    return function(scope, locals, assign, inputs) {
26213      var arg = argument(scope, locals, assign, inputs);
26214      if (isDefined(arg)) {
26215        arg = -arg;
26216      } else {
26217        arg = -0;
26218      }
26219      return context ? {value: arg} : arg;
26220    };
26221  },
26222  'unary!': function(argument, context) {
26223    return function(scope, locals, assign, inputs) {
26224      var arg = !argument(scope, locals, assign, inputs);
26225      return context ? {value: arg} : arg;
26226    };
26227  },
26228  'binary+': function(left, right, context) {
26229    return function(scope, locals, assign, inputs) {
26230      var lhs = left(scope, locals, assign, inputs);
26231      var rhs = right(scope, locals, assign, inputs);
26232      var arg = plusFn(lhs, rhs);
26233      return context ? {value: arg} : arg;
26234    };
26235  },
26236  'binary-': function(left, right, context) {
26237    return function(scope, locals, assign, inputs) {
26238      var lhs = left(scope, locals, assign, inputs);
26239      var rhs = right(scope, locals, assign, inputs);
26240      var arg = (isDefined(lhs) ? lhs : 0) - (isDefined(rhs) ? rhs : 0);
26241      return context ? {value: arg} : arg;
26242    };
26243  },
26244  'binary*': function(left, right, context) {
26245    return function(scope, locals, assign, inputs) {
26246      var arg = left(scope, locals, assign, inputs) * right(scope, locals, assign, inputs);
26247      return context ? {value: arg} : arg;
26248    };
26249  },
26250  'binary/': function(left, right, context) {
26251    return function(scope, locals, assign, inputs) {
26252      var arg = left(scope, locals, assign, inputs) / right(scope, locals, assign, inputs);
26253      return context ? {value: arg} : arg;
26254    };
26255  },
26256  'binary%': function(left, right, context) {
26257    return function(scope, locals, assign, inputs) {
26258      var arg = left(scope, locals, assign, inputs) % right(scope, locals, assign, inputs);
26259      return context ? {value: arg} : arg;
26260    };
26261  },
26262  'binary===': function(left, right, context) {
26263    return function(scope, locals, assign, inputs) {
26264      var arg = left(scope, locals, assign, inputs) === right(scope, locals, assign, inputs);
26265      return context ? {value: arg} : arg;
26266    };
26267  },
26268  'binary!==': function(left, right, context) {
26269    return function(scope, locals, assign, inputs) {
26270      var arg = left(scope, locals, assign, inputs) !== right(scope, locals, assign, inputs);
26271      return context ? {value: arg} : arg;
26272    };
26273  },
26274  'binary==': function(left, right, context) {
26275    return function(scope, locals, assign, inputs) {
26276      // eslint-disable-next-line eqeqeq
26277      var arg = left(scope, locals, assign, inputs) == right(scope, locals, assign, inputs);
26278      return context ? {value: arg} : arg;
26279    };
26280  },
26281  'binary!=': function(left, right, context) {
26282    return function(scope, locals, assign, inputs) {
26283      // eslint-disable-next-line eqeqeq
26284      var arg = left(scope, locals, assign, inputs) != right(scope, locals, assign, inputs);
26285      return context ? {value: arg} : arg;
26286    };
26287  },
26288  'binary<': function(left, right, context) {
26289    return function(scope, locals, assign, inputs) {
26290      var arg = left(scope, locals, assign, inputs) < right(scope, locals, assign, inputs);
26291      return context ? {value: arg} : arg;
26292    };
26293  },
26294  'binary>': function(left, right, context) {
26295    return function(scope, locals, assign, inputs) {
26296      var arg = left(scope, locals, assign, inputs) > right(scope, locals, assign, inputs);
26297      return context ? {value: arg} : arg;
26298    };
26299  },
26300  'binary<=': function(left, right, context) {
26301    return function(scope, locals, assign, inputs) {
26302      var arg = left(scope, locals, assign, inputs) <= right(scope, locals, assign, inputs);
26303      return context ? {value: arg} : arg;
26304    };
26305  },
26306  'binary>=': function(left, right, context) {
26307    return function(scope, locals, assign, inputs) {
26308      var arg = left(scope, locals, assign, inputs) >= right(scope, locals, assign, inputs);
26309      return context ? {value: arg} : arg;
26310    };
26311  },
26312  'binary&&': function(left, right, context) {
26313    return function(scope, locals, assign, inputs) {
26314      var arg = left(scope, locals, assign, inputs) && right(scope, locals, assign, inputs);
26315      return context ? {value: arg} : arg;
26316    };
26317  },
26318  'binary||': function(left, right, context) {
26319    return function(scope, locals, assign, inputs) {
26320      var arg = left(scope, locals, assign, inputs) || right(scope, locals, assign, inputs);
26321      return context ? {value: arg} : arg;
26322    };
26323  },
26324  'ternary?:': function(test, alternate, consequent, context) {
26325    return function(scope, locals, assign, inputs) {
26326      var arg = test(scope, locals, assign, inputs) ? alternate(scope, locals, assign, inputs) : consequent(scope, locals, assign, inputs);
26327      return context ? {value: arg} : arg;
26328    };
26329  },
26330  value: function(value, context) {
26331    return function() { return context ? {context: undefined, name: undefined, value: value} : value; };
26332  },
26333  identifier: function(name, context, create) {
26334    return function(scope, locals, assign, inputs) {
26335      var base = locals && (name in locals) ? locals : scope;
26336      if (create && create !== 1 && base && base[name] == null) {
26337        base[name] = {};
26338      }
26339      var value = base ? base[name] : undefined;
26340      if (context) {
26341        return {context: base, name: name, value: value};
26342      } else {
26343        return value;
26344      }
26345    };
26346  },
26347  computedMember: function(left, right, context, create) {
26348    return function(scope, locals, assign, inputs) {
26349      var lhs = left(scope, locals, assign, inputs);
26350      var rhs;
26351      var value;
26352      if (lhs != null) {
26353        rhs = right(scope, locals, assign, inputs);
26354        rhs = getStringValue(rhs);
26355        if (create && create !== 1) {
26356          if (lhs && !(lhs[rhs])) {
26357            lhs[rhs] = {};
26358          }
26359        }
26360        value = lhs[rhs];
26361      }
26362      if (context) {
26363        return {context: lhs, name: rhs, value: value};
26364      } else {
26365        return value;
26366      }
26367    };
26368  },
26369  nonComputedMember: function(left, right, context, create) {
26370    return function(scope, locals, assign, inputs) {
26371      var lhs = left(scope, locals, assign, inputs);
26372      if (create && create !== 1) {
26373        if (lhs && lhs[right] == null) {
26374          lhs[right] = {};
26375        }
26376      }
26377      var value = lhs != null ? lhs[right] : undefined;
26378      if (context) {
26379        return {context: lhs, name: right, value: value};
26380      } else {
26381        return value;
26382      }
26383    };
26384  },
26385  inputs: function(input, watchId) {
26386    return function(scope, value, locals, inputs) {
26387      if (inputs) return inputs[watchId];
26388      return input(scope, value, locals);
26389    };
26390  }
26391};
26392
26393/**
26394 * @constructor
26395 */
26396var Parser = function Parser(lexer, $filter, options) {
26397  this.lexer = lexer;
26398  this.$filter = $filter;
26399  this.options = options;
26400  this.ast = new AST(lexer, options);
26401  this.astCompiler = options.csp ? new ASTInterpreter(this.ast, $filter) :
26402                                   new ASTCompiler(this.ast, $filter);
26403};
26404
26405Parser.prototype = {
26406  constructor: Parser,
26407
26408  parse: function(text) {
26409    return this.astCompiler.compile(text);
26410  }
26411};
26412
26413function getValueOf(value) {
26414  return isFunction(value.valueOf) ? value.valueOf() : objectValueOf.call(value);
26415}
26416
26417///////////////////////////////////
26418
26419/**
26420 * @ngdoc service
26421 * @name $parse
26422 * @kind function
26423 *
26424 * @description
26425 *
26426 * Converts Angular {@link guide/expression expression} into a function.
26427 *
26428 * ```js
26429 *   var getter = $parse('user.name');
26430 *   var setter = getter.assign;
26431 *   var context = {user:{name:'angular'}};
26432 *   var locals = {user:{name:'local'}};
26433 *
26434 *   expect(getter(context)).toEqual('angular');
26435 *   setter(context, 'newValue');
26436 *   expect(context.user.name).toEqual('newValue');
26437 *   expect(getter(context, locals)).toEqual('local');
26438 * ```
26439 *
26440 *
26441 * @param {string} expression String expression to compile.
26442 * @returns {function(context, locals)} a function which represents the compiled expression:
26443 *
26444 *    * `context` – `{object}` – an object against which any expressions embedded in the strings
26445 *      are evaluated against (typically a scope object).
26446 *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
26447 *      `context`.
26448 *
26449 *    The returned function also has the following properties:
26450 *      * `literal` – `{boolean}` – whether the expression's top-level node is a JavaScript
26451 *        literal.
26452 *      * `constant` – `{boolean}` – whether the expression is made entirely of JavaScript
26453 *        constant literals.
26454 *      * `assign` – `{?function(context, value)}` – if the expression is assignable, this will be
26455 *        set to a function to change its value on the given context.
26456 *
26457 */
26458
26459
26460/**
26461 * @ngdoc provider
26462 * @name $parseProvider
26463 * @this
26464 *
26465 * @description
26466 * `$parseProvider` can be used for configuring the default behavior of the {@link ng.$parse $parse}
26467 *  service.
26468 */
26469function $ParseProvider() {
26470  var cache = createMap();
26471  var literals = {
26472    'true': true,
26473    'false': false,
26474    'null': null,
26475    'undefined': undefined
26476  };
26477  var identStart, identContinue;
26478
26479  /**
26480   * @ngdoc method
26481   * @name $parseProvider#addLiteral
26482   * @description
26483   *
26484   * Configure $parse service to add literal values that will be present as literal at expressions.
26485   *
26486   * @param {string} literalName Token for the literal value. The literal name value must be a valid literal name.
26487   * @param {*} literalValue Value for this literal. All literal values must be primitives or `undefined`.
26488   *
26489   **/
26490  this.addLiteral = function(literalName, literalValue) {
26491    literals[literalName] = literalValue;
26492  };
26493
26494 /**
26495  * @ngdoc method
26496  * @name $parseProvider#setIdentifierFns
26497  *
26498  * @description
26499  *
26500  * Allows defining the set of characters that are allowed in Angular expressions. The function
26501  * `identifierStart` will get called to know if a given character is a valid character to be the
26502  * first character for an identifier. The function `identifierContinue` will get called to know if
26503  * a given character is a valid character to be a follow-up identifier character. The functions
26504  * `identifierStart` and `identifierContinue` will receive as arguments the single character to be
26505  * identifier and the character code point. These arguments will be `string` and `numeric`. Keep in
26506  * mind that the `string` parameter can be two characters long depending on the character
26507  * representation. It is expected for the function to return `true` or `false`, whether that
26508  * character is allowed or not.
26509  *
26510  * Since this function will be called extensively, keep the implementation of these functions fast,
26511  * as the performance of these functions have a direct impact on the expressions parsing speed.
26512  *
26513  * @param {function=} identifierStart The function that will decide whether the given character is
26514  *   a valid identifier start character.
26515  * @param {function=} identifierContinue The function that will decide whether the given character is
26516  *   a valid identifier continue character.
26517  */
26518  this.setIdentifierFns = function(identifierStart, identifierContinue) {
26519    identStart = identifierStart;
26520    identContinue = identifierContinue;
26521    return this;
26522  };
26523
26524  this.$get = ['$filter', function($filter) {
26525    var noUnsafeEval = csp().noUnsafeEval;
26526    var $parseOptions = {
26527          csp: noUnsafeEval,
26528          literals: copy(literals),
26529          isIdentifierStart: isFunction(identStart) && identStart,
26530          isIdentifierContinue: isFunction(identContinue) && identContinue
26531        };
26532    return $parse;
26533
26534    function $parse(exp, interceptorFn) {
26535      var parsedExpression, oneTime, cacheKey;
26536
26537      switch (typeof exp) {
26538        case 'string':
26539          exp = exp.trim();
26540          cacheKey = exp;
26541
26542          parsedExpression = cache[cacheKey];
26543
26544          if (!parsedExpression) {
26545            if (exp.charAt(0) === ':' && exp.charAt(1) === ':') {
26546              oneTime = true;
26547              exp = exp.substring(2);
26548            }
26549            var lexer = new Lexer($parseOptions);
26550            var parser = new Parser(lexer, $filter, $parseOptions);
26551            parsedExpression = parser.parse(exp);
26552            if (parsedExpression.constant) {
26553              parsedExpression.$$watchDelegate = constantWatchDelegate;
26554            } else if (oneTime) {
26555              parsedExpression.$$watchDelegate = parsedExpression.literal ?
26556                  oneTimeLiteralWatchDelegate : oneTimeWatchDelegate;
26557            } else if (parsedExpression.inputs) {
26558              parsedExpression.$$watchDelegate = inputsWatchDelegate;
26559            }
26560            cache[cacheKey] = parsedExpression;
26561          }
26562          return addInterceptor(parsedExpression, interceptorFn);
26563
26564        case 'function':
26565          return addInterceptor(exp, interceptorFn);
26566
26567        default:
26568          return addInterceptor(noop, interceptorFn);
26569      }
26570    }
26571
26572    function expressionInputDirtyCheck(newValue, oldValueOfValue, compareObjectIdentity) {
26573
26574      if (newValue == null || oldValueOfValue == null) { // null/undefined
26575        return newValue === oldValueOfValue;
26576      }
26577
26578      if (typeof newValue === 'object' && !compareObjectIdentity) {
26579
26580        // attempt to convert the value to a primitive type
26581        // TODO(docs): add a note to docs that by implementing valueOf even objects and arrays can
26582        //             be cheaply dirty-checked
26583        newValue = getValueOf(newValue);
26584
26585        if (typeof newValue === 'object') {
26586          // objects/arrays are not supported - deep-watching them would be too expensive
26587          return false;
vendor: 2,350 bytes, lines 26588-26643
26588        }
26589
26590        // fall-through to the primitive equality check
26591      }
26592
26593      //Primitive or NaN
26594      // eslint-disable-next-line no-self-compare
26595      return newValue === oldValueOfValue || (newValue !== newValue && oldValueOfValue !== oldValueOfValue);
26596    }
26597
26598    function inputsWatchDelegate(scope, listener, objectEquality, parsedExpression, prettyPrintExpression) {
26599      var inputExpressions = parsedExpression.inputs;
26600      var lastResult;
26601
26602      if (inputExpressions.length === 1) {
26603        var oldInputValueOf = expressionInputDirtyCheck; // init to something unique so that equals check fails
26604        inputExpressions = inputExpressions[0];
26605        return scope.$watch(function expressionInputWatch(scope) {
26606          var newInputValue = inputExpressions(scope);
26607          if (!expressionInputDirtyCheck(newInputValue, oldInputValueOf, parsedExpression.literal)) {
26608            lastResult = parsedExpression(scope, undefined, undefined, [newInputValue]);
26609            oldInputValueOf = newInputValue && getValueOf(newInputValue);
26610          }
26611          return lastResult;
26612        }, listener, objectEquality, prettyPrintExpression);
26613      }
26614
26615      var oldInputValueOfValues = [];
26616      var oldInputValues = [];
26617      for (var i = 0, ii = inputExpressions.length; i < ii; i++) {
26618        oldInputValueOfValues[i] = expressionInputDirtyCheck; // init to something unique so that equals check fails
26619        oldInputValues[i] = null;
26620      }
26621
26622      return scope.$watch(function expressionInputsWatch(scope) {
26623        var changed = false;
26624
26625        for (var i = 0, ii = inputExpressions.length; i < ii; i++) {
26626          var newInputValue = inputExpressions[i](scope);
26627          if (changed || (changed = !expressionInputDirtyCheck(newInputValue, oldInputValueOfValues[i], parsedExpression.literal))) {
26628            oldInputValues[i] = newInputValue;
26629            oldInputValueOfValues[i] = newInputValue && getValueOf(newInputValue);
26630          }
26631        }
26632
26633        if (changed) {
26634          lastResult = parsedExpression(scope, undefined, undefined, oldInputValues);
26635        }
26636
26637        return lastResult;
26638      }, listener, objectEquality, prettyPrintExpression);
26639    }
26640
26641    function oneTimeWatchDelegate(scope, listener, objectEquality, parsedExpression, prettyPrintExpression) {
26642      var unwatch, lastValue;
26643      if (parsedExpression.inputs) {
26644        unwatch = inputsWatchDelegate(scope, oneTimeListener, objectEquality, parsedExpression, prettyPrintExpression);
26645      } else {
26646        unwatch = scope.$watch(oneTimeWatch, oneTimeListener, objectEquality);
26647      }
26648      return unwatch;
26649
26650      function oneTimeWatch(scope) {
26651        return parsedExpression(scope);
26652      }
26653      function oneTimeListener(value, old, scope) {
26654        lastValue = value;
26655        if (isFunction(listener)) {
26656          listener(value, old, scope);
26657        }
26658        if (isDefined(value)) {
26659          scope.$$postDigest(function() {
26660            if (isDefined(lastValue)) {
26661              unwatch();
26662            }
26663          });
26664        }
26665      }
26666    }
26667
26668    function oneTimeLiteralWatchDelegate(scope, listener, objectEquality, parsedExpression) {
26669      var unwatch, lastValue;
26670      unwatch = scope.$watch(function oneTimeWatch(scope) {
26671        return parsedExpression(scope);
26672      }, function oneTimeListener(value, old, scope) {
26673        lastValue = value;
26674        if (isFunction(listener)) {
26675          listener(value, old, scope);
26676        }
26677        if (isAllDefined(value)) {
26678          scope.$$postDigest(function() {
26679            if (isAllDefined(lastValue)) unwatch();
26680          });
26681        }
26682      }, objectEquality);
26683
26684      return unwatch;
26685
26686      function isAllDefined(value) {
26687        var allDefined = true;
26688        forEach(value, function(val) {
26689          if (!isDefined(val)) allDefined = false;
26690        });
26691        return allDefined;
26692      }
26693    }
26694
26695    function constantWatchDelegate(scope, listener, objectEquality, parsedExpression) {
26696      var unwatch = scope.$watch(function constantWatch(scope) {
26697        unwatch();
26698        return parsedExpression(scope);
26699      }, listener, objectEquality);
26700      return unwatch;
26701    }
26702
26703    function addInterceptor(parsedExpression, interceptorFn) {
26704      if (!interceptorFn) return parsedExpression;
26705      var watchDelegate = parsedExpression.$$watchDelegate;
26706      var useInputs = false;
26707
26708      var regularWatch =
26709          watchDelegate !== oneTimeLiteralWatchDelegate &&
26710          watchDelegate !== oneTimeWatchDelegate;
26711
26712      var fn = regularWatch ? function regularInterceptedExpression(scope, locals, assign, inputs) {
26713        var value = useInputs && inputs ? inputs[0] : parsedExpression(scope, locals, assign, inputs);
26714        return interceptorFn(value, scope, locals);
26715      } : function oneTimeInterceptedExpression(scope, locals, assign, inputs) {
26716        var value = parsedExpression(scope, locals, assign, inputs);
26717        var result = interceptorFn(value, scope, locals);
26718        // we only return the interceptor's result if the
26719        // initial value is defined (for bind-once)
26720        return isDefined(value) ? result : value;
26721      };
26722
26723      // Propagate $$watchDelegates other then inputsWatchDelegate
26724      useInputs = !parsedExpression.inputs;
26725      if (parsedExpression.$$watchDelegate &&
26726          parsedExpression.$$watchDelegate !== inputsWatchDelegate) {
26727        fn.$$watchDelegate = parsedExpression.$$watchDelegate;
26728        fn.inputs = parsedExpression.inputs;
26729      } else if (!interceptorFn.$stateful) {
26730        // If there is an interceptor, but no watchDelegate then treat the interceptor like
26731        // we treat filters - it is assumed to be a pure function unless flagged with $stateful
26732        fn.$$watchDelegate = inputsWatchDelegate;
26733        fn.inputs = parsedExpression.inputs ? parsedExpression.inputs : [parsedExpression];
26734      }
26735
26736      return fn;
26737    }
26738  }];
26739}
26740
26741/**
26742 * @ngdoc service
26743 * @name $q
26744 * @requires $rootScope
26745 *
26746 * @description
26747 * A service that helps you run functions asynchronously, and use their return values (or exceptions)
26748 * when they are done processing.
26749 *
26750 * This is a [Promises/A+](https://promisesaplus.com/)-compliant implementation of promises/deferred
26751 * objects inspired by [Kris Kowal's Q](https://github.com/kriskowal/q).
26752 *
26753 * $q can be used in two fashions --- one which is more similar to Kris Kowal's Q or jQuery's Deferred
26754 * implementations, and the other which resembles ES6 (ES2015) promises to some degree.
26755 *
26756 * # $q constructor
26757 *
26758 * The streamlined ES6 style promise is essentially just using $q as a constructor which takes a `resolver`
26759 * function as the first argument. This is similar to the native Promise implementation from ES6,
26760 * see [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise).
26761 *
26762 * While the constructor-style use is supported, not all of the supporting methods from ES6 promises are
26763 * available yet.
26764 *
26765 * It can be used like so:
26766 *
26767 * ```js
26768 *   // for the purpose of this example let's assume that variables `$q` and `okToGreet`
26769 *   // are available in the current lexical scope (they could have been injected or passed in).
26770 *
26771 *   function asyncGreet(name) {
26772 *     // perform some asynchronous operation, resolve or reject the promise when appropriate.
26773 *     return $q(function(resolve, reject) {
26774 *       setTimeout(function() {
26775 *         if (okToGreet(name)) {
26776 *           resolve('Hello, ' + name + '!');
26777 *         } else {
26778 *           reject('Greeting ' + name + ' is not allowed.');
26779 *         }
26780 *       }, 1000);
26781 *     });
26782 *   }
26783 *
26784 *   var promise = asyncGreet('Robin Hood');
26785 *   promise.then(function(greeting) {
26786 *     alert('Success: ' + greeting);
26787 *   }, function(reason) {
26788 *     alert('Failed: ' + reason);
26789 *   });
26790 * ```
26791 *
26792 * Note: progress/notify callbacks are not currently supported via the ES6-style interface.
26793 *
26794 * Note: unlike ES6 behavior, an exception thrown in the constructor function will NOT implicitly reject the promise.
26795 *
26796 * However, the more traditional CommonJS-style usage is still available, and documented below.
26797 *
26798 * [The CommonJS Promise proposal](http://wiki.commonjs.org/wiki/Promises) describes a promise as an
26799 * interface for interacting with an object that represents the result of an action that is
26800 * performed asynchronously, and may or may not be finished at any given point in time.
26801 *
26802 * From the perspective of dealing with error handling, deferred and promise APIs are to
26803 * asynchronous programming what `try`, `catch` and `throw` keywords are to synchronous programming.
26804 *
26805 * ```js
26806 *   // for the purpose of this example let's assume that variables `$q` and `okToGreet`
26807 *   // are available in the current lexical scope (they could have been injected or passed in).
26808 *
26809 *   function asyncGreet(name) {
26810 *     var deferred = $q.defer();
26811 *
26812 *     setTimeout(function() {
26813 *       deferred.notify('About to greet ' + name + '.');
26814 *
26815 *       if (okToGreet(name)) {
26816 *         deferred.resolve('Hello, ' + name + '!');
26817 *       } else {
26818 *         deferred.reject('Greeting ' + name + ' is not allowed.');
26819 *       }
26820 *     }, 1000);
26821 *
26822 *     return deferred.promise;
26823 *   }
26824 *
26825 *   var promise = asyncGreet('Robin Hood');
26826 *   promise.then(function(greeting) {
26827 *     alert('Success: ' + greeting);
26828 *   }, function(reason) {
26829 *     alert('Failed: ' + reason);
26830 *   }, function(update) {
26831 *     alert('Got notification: ' + update);
26832 *   });
26833 * ```
26834 *
26835 * At first it might not be obvious why this extra complexity is worth the trouble. The payoff
26836 * comes in the way of guarantees that promise and deferred APIs make, see
26837 * https://github.com/kriskowal/uncommonjs/blob/master/promises/specification.md.
26838 *
26839 * Additionally the promise api allows for composition that is very hard to do with the
26840 * traditional callback ([CPS](http://en.wikipedia.org/wiki/Continuation-passing_style)) approach.
26841 * For more on this please see the [Q documentation](https://github.com/kriskowal/q) especially the
26842 * section on serial or parallel joining of promises.
26843 *
26844 * # The Deferred API
26845 *
26846 * A new instance of deferred is constructed by calling `$q.defer()`.
26847 *
26848 * The purpose of the deferred object is to expose the associated Promise instance as well as APIs
26849 * that can be used for signaling the successful or unsuccessful completion, as well as the status
26850 * of the task.
26851 *
26852 * **Methods**
26853 *
26854 * - `resolve(value)` – resolves the derived promise with the `value`. If the value is a rejection
26855 *   constructed via `$q.reject`, the promise will be rejected instead.
26856 * - `reject(reason)` – rejects the derived promise with the `reason`. This is equivalent to
26857 *   resolving it with a rejection constructed via `$q.reject`.
26858 * - `notify(value)` - provides updates on the status of the promise's execution. This may be called
26859 *   multiple times before the promise is either resolved or rejected.
26860 *
26861 * **Properties**
26862 *
26863 * - promise – `{Promise}` – promise object associated with this deferred.
26864 *
26865 *
26866 * # The Promise API
26867 *
26868 * A new promise instance is created when a deferred instance is created and can be retrieved by
26869 * calling `deferred.promise`.
26870 *
26871 * The purpose of the promise object is to allow for interested parties to get access to the result
26872 * of the deferred task when it completes.
26873 *
26874 * **Methods**
26875 *
26876 * - `then(successCallback, [errorCallback], [notifyCallback])` – regardless of when the promise was or
26877 *   will be resolved or rejected, `then` calls one of the success or error callbacks asynchronously
26878 *   as soon as the result is available. The callbacks are called with a single argument: the result
26879 *   or rejection reason. Additionally, the notify callback may be called zero or more times to
26880 *   provide a progress indication, before the promise is resolved or rejected.
26881 *
26882 *   This method *returns a new promise* which is resolved or rejected via the return value of the
26883 *   `successCallback`, `errorCallback` (unless that value is a promise, in which case it is resolved
26884 *   with the value which is resolved in that promise using
26885 *   [promise chaining](http://www.html5rocks.com/en/tutorials/es6/promises/#toc-promises-queues)).
26886 *   It also notifies via the return value of the `notifyCallback` method. The promise cannot be
26887 *   resolved or rejected from the notifyCallback method. The errorCallback and notifyCallback
26888 *   arguments are optional.
26889 *
26890 * - `catch(errorCallback)` – shorthand for `promise.then(null, errorCallback)`
26891 *
26892 * - `finally(callback, notifyCallback)` – allows you to observe either the fulfillment or rejection of a promise,
26893 *   but to do so without modifying the final value. This is useful to release resources or do some
26894 *   clean-up that needs to be done whether the promise was rejected or resolved. See the [full
26895 *   specification](https://github.com/kriskowal/q/wiki/API-Reference#promisefinallycallback) for
26896 *   more information.
26897 *
26898 * # Chaining promises
26899 *
26900 * Because calling the `then` method of a promise returns a new derived promise, it is easily
26901 * possible to create a chain of promises:
26902 *
26903 * ```js
26904 *   promiseB = promiseA.then(function(result) {
26905 *     return result + 1;
26906 *   });
26907 *
26908 *   // promiseB will be resolved immediately after promiseA is resolved and its value
26909 *   // will be the result of promiseA incremented by 1
26910 * ```
26911 *
26912 * It is possible to create chains of any length and since a promise can be resolved with another
26913 * promise (which will defer its resolution further), it is possible to pause/defer resolution of
26914 * the promises at any point in the chain. This makes it possible to implement powerful APIs like
26915 * $http's response interceptors.
26916 *
26917 *
26918 * # Differences between Kris Kowal's Q and $q
26919 *
26920 *  There are two main differences:
26921 *
26922 * - $q is integrated with the {@link ng.$rootScope.Scope} Scope model observation
26923 *   mechanism in angular, which means faster propagation of resolution or rejection into your
26924 *   models and avoiding unnecessary browser repaints, which would result in flickering UI.
26925 * - Q has many more features than $q, but that comes at a cost of bytes. $q is tiny, but contains
26926 *   all the important functionality needed for common async tasks.
26927 *
26928 * # Testing
26929 *
26930 *  ```js
26931 *    it('should simulate promise', inject(function($q, $rootScope) {
26932 *      var deferred = $q.defer();
26933 *      var promise = deferred.promise;
26934 *      var resolvedValue;
26935 *
26936 *      promise.then(function(value) { resolvedValue = value; });
26937 *      expect(resolvedValue).toBeUndefined();
26938 *
26939 *      // Simulate resolving of promise
26940 *      deferred.resolve(123);
26941 *      // Note that the 'then' function does not get called synchronously.
26942 *      // This is because we want the promise API to always be async, whether or not
26943 *      // it got called synchronously or asynchronously.
26944 *      expect(resolvedValue).toBeUndefined();
26945 *
26946 *      // Propagate promise resolution to 'then' functions using $apply().
26947 *      $rootScope.$apply();
26948 *      expect(resolvedValue).toEqual(123);
26949 *    }));
26950 *  ```
26951 *
26952 * @param {function(function, function)} resolver Function which is responsible for resolving or
26953 *   rejecting the newly created promise. The first parameter is a function which resolves the
26954 *   promise, the second parameter is a function which rejects the promise.
26955 *
26956 * @returns {Promise} The newly created promise.
26957 */
26958/**
26959 * @ngdoc provider
26960 * @name $qProvider
26961 * @this
26962 *
26963 * @description
26964 */
26965function $QProvider() {
26966  var errorOnUnhandledRejections = true;
26967  this.$get = ['$rootScope', '$exceptionHandler', function($rootScope, $exceptionHandler) {
26968    return qFactory(function(callback) {
26969      $rootScope.$evalAsync(callback);
26970    }, $exceptionHandler, errorOnUnhandledRejections);
26971  }];
26972
26973  /**
26974   * @ngdoc method
26975   * @name $qProvider#errorOnUnhandledRejections
26976   * @kind function
26977   *
26978   * @description
26979   * Retrieves or overrides whether to generate an error when a rejected promise is not handled.
26980   * This feature is enabled by default.
26981   *
26982   * @param {boolean=} value Whether to generate an error when a rejected promise is not handled.
26983   * @returns {boolean|ng.$qProvider} Current value when called without a new value or self for
26984   *    chaining otherwise.
26985   */
26986  this.errorOnUnhandledRejections = function(value) {
26987    if (isDefined(value)) {
26988      errorOnUnhandledRejections = value;
26989      return this;
26990    } else {
26991      return errorOnUnhandledRejections;
26992    }
26993  };
26994}
26995
26996/** @this */
26997function $$QProvider() {
26998  var errorOnUnhandledRejections = true;
26999  this.$get = ['$browser', '$exceptionHandler', function($browser, $exceptionHandler) {
27000    return qFactory(function(callback) {
27001      $browser.defer(callback);
27002    }, $exceptionHandler, errorOnUnhandledRejections);
27003  }];
27004
27005  this.errorOnUnhandledRejections = function(value) {
27006    if (isDefined(value)) {
27007      errorOnUnhandledRejections = value;
27008      return this;
27009    } else {
27010      return errorOnUnhandledRejections;
27011    }
27012  };
27013}
27014
27015/**
27016 * Constructs a promise manager.
27017 *
27018 * @param {function(function)} nextTick Function for executing functions in the next turn.
27019 * @param {function(...*)} exceptionHandler Function into which unexpected exceptions are passed for
27020 *     debugging purposes.
27021 @ param {=boolean} errorOnUnhandledRejections Whether an error should be generated on unhandled
27022 *     promises rejections.
27023 * @returns {object} Promise manager.
27024 */
27025function qFactory(nextTick, exceptionHandler, errorOnUnhandledRejections) {
27026  var $qMinErr = minErr('$q', TypeError);
27027  var queueSize = 0;
27028  var checkQueue = [];
27029
27030  /**
27031   * @ngdoc method
27032   * @name ng.$q#defer
27033   * @kind function
27034   *
27035   * @description
27036   * Creates a `Deferred` object which represents a task which will finish in the future.
27037   *
27038   * @returns {Deferred} Returns a new instance of deferred.
27039   */
27040  function defer() {
27041    return new Deferred();
27042  }
27043
27044  function Deferred() {
27045    var promise = this.promise = new Promise();
27046    //Non prototype methods necessary to support unbound execution :/
27047    this.resolve = function(val) { resolvePromise(promise, val); };
27048    this.reject = function(reason) { rejectPromise(promise, reason); };
27049    this.notify = function(progress) { notifyPromise(promise, progress); };
27050  }
27051
27052
27053  function Promise() {
27054    this.$$state = { status: 0 };
27055  }
27056
27057  extend(Promise.prototype, {
27058    then: function(onFulfilled, onRejected, progressBack) {
27059      if (isUndefined(onFulfilled) && isUndefined(onRejected) && isUndefined(progressBack)) {
27060        return this;
27061      }
27062      var result = new Promise();
27063
27064      this.$$state.pending = this.$$state.pending || [];
27065      this.$$state.pending.push([result, onFulfilled, onRejected, progressBack]);
vendor: 5,152 bytes, lines 27066-27241
27066      if (this.$$state.status > 0) scheduleProcessQueue(this.$$state);
27067
27068      return result;
27069    },
27070
27071    'catch': function(callback) {
27072      return this.then(null, callback);
27073    },
27074
27075    'finally': function(callback, progressBack) {
27076      return this.then(function(value) {
27077        return handleCallback(value, resolve, callback);
27078      }, function(error) {
27079        return handleCallback(error, reject, callback);
27080      }, progressBack);
27081    }
27082  });
27083
27084  function processQueue(state) {
27085    var fn, promise, pending;
27086
27087    pending = state.pending;
27088    state.processScheduled = false;
27089    state.pending = undefined;
27090    try {
27091      for (var i = 0, ii = pending.length; i < ii; ++i) {
27092        state.pur = true;
27093        promise = pending[i][0];
27094        fn = pending[i][state.status];
27095        try {
27096          if (isFunction(fn)) {
27097            resolvePromise(promise, fn(state.value));
27098          } else if (state.status === 1) {
27099            resolvePromise(promise, state.value);
27100          } else {
27101            rejectPromise(promise, state.value);
27102          }
27103        } catch (e) {
27104          rejectPromise(promise, e);
27105        }
27106      }
27107    } finally {
27108      --queueSize;
27109      if (errorOnUnhandledRejections && queueSize === 0) {
27110        nextTick(processChecks);
27111      }
27112    }
27113  }
27114
27115  function processChecks() {
27116    // eslint-disable-next-line no-unmodified-loop-condition
27117    while (!queueSize && checkQueue.length) {
27118      var toCheck = checkQueue.shift();
27119      if (!toCheck.pur) {
27120        toCheck.pur = true;
27121        var errorMessage = 'Possibly unhandled rejection: ' + toDebugString(toCheck.value);
27122        if (toCheck.value instanceof Error) {
27123          exceptionHandler(toCheck.value, errorMessage);
27124        } else {
27125          exceptionHandler(errorMessage);
27126        }
27127      }
27128    }
27129  }
27130
27131  function scheduleProcessQueue(state) {
27132    if (errorOnUnhandledRejections && !state.pending && state.status === 2 && !state.pur) {
27133      if (queueSize === 0 && checkQueue.length === 0) {
27134        nextTick(processChecks);
27135      }
27136      checkQueue.push(state);
27137    }
27138    if (state.processScheduled || !state.pending) return;
27139    state.processScheduled = true;
27140    ++queueSize;
27141    nextTick(function() { processQueue(state); });
27142  }
27143
27144  function resolvePromise(promise, val) {
27145    if (promise.$$state.status) return;
27146    if (val === promise) {
27147      $$reject(promise, $qMinErr(
27148        'qcycle',
27149        'Expected promise to be resolved with value other than itself \'{0}\'',
27150        val));
27151    } else {
27152      $$resolve(promise, val);
27153    }
27154
27155  }
27156
27157  function $$resolve(promise, val) {
27158    var then;
27159    var done = false;
27160    try {
27161      if (isObject(val) || isFunction(val)) then = val.then;
27162      if (isFunction(then)) {
27163        promise.$$state.status = -1;
27164        then.call(val, doResolve, doReject, doNotify);
27165      } else {
27166        promise.$$state.value = val;
27167        promise.$$state.status = 1;
27168        scheduleProcessQueue(promise.$$state);
27169      }
27170    } catch (e) {
27171      doReject(e);
27172    }
27173
27174    function doResolve(val) {
27175      if (done) return;
27176      done = true;
27177      $$resolve(promise, val);
27178    }
27179    function doReject(val) {
27180      if (done) return;
27181      done = true;
27182      $$reject(promise, val);
27183    }
27184    function doNotify(progress) {
27185      notifyPromise(promise, progress);
27186    }
27187  }
27188
27189  function rejectPromise(promise, reason) {
27190    if (promise.$$state.status) return;
27191    $$reject(promise, reason);
27192  }
27193
27194  function $$reject(promise, reason) {
27195    promise.$$state.value = reason;
27196    promise.$$state.status = 2;
27197    scheduleProcessQueue(promise.$$state);
27198  }
27199
27200  function notifyPromise(promise, progress) {
27201    var callbacks = promise.$$state.pending;
27202
27203    if ((promise.$$state.status <= 0) && callbacks && callbacks.length) {
27204      nextTick(function() {
27205        var callback, result;
27206        for (var i = 0, ii = callbacks.length; i < ii; i++) {
27207          result = callbacks[i][0];
27208          callback = callbacks[i][3];
27209          try {
27210            notifyPromise(result, isFunction(callback) ? callback(progress) : progress);
27211          } catch (e) {
27212            exceptionHandler(e);
27213          }
27214        }
27215      });
27216    }
27217  }
27218
27219  /**
27220   * @ngdoc method
27221   * @name $q#reject
27222   * @kind function
27223   *
27224   * @description
27225   * Creates a promise that is resolved as rejected with the specified `reason`. This api should be
27226   * used to forward rejection in a chain of promises. If you are dealing with the last promise in
27227   * a promise chain, you don't need to worry about it.
27228   *
27229   * When comparing deferreds/promises to the familiar behavior of try/catch/throw, think of
27230   * `reject` as the `throw` keyword in JavaScript. This also means that if you "catch" an error via
27231   * a promise error callback and you want to forward the error to the promise derived from the
27232   * current promise, you have to "rethrow" the error by returning a rejection constructed via
27233   * `reject`.
27234   *
27235   * ```js
27236   *   promiseB = promiseA.then(function(result) {
27237   *     // success: do something and resolve promiseB
27238   *     //          with the old or a new result
27239   *     return result;
27240   *   }, function(reason) {
27241   *     // error: handle the error if possible and
27242   *     //        resolve promiseB with newPromiseOrValue,
27243   *     //        otherwise forward the rejection to promiseB
27244   *     if (canHandle(reason)) {
27245   *      // handle the error and recover
27246   *      return newPromiseOrValue;
27247   *     }
27248   *     return $q.reject(reason);
27249   *   });
27250   * ```
27251   *
27252   * @param {*} reason Constant, message, exception or an object representing the rejection reason.
27253   * @returns {Promise} Returns a promise that was already resolved as rejected with the `reason`.
27254   */
27255  function reject(reason) {
27256    var result = new Promise();
27257    rejectPromise(result, reason);
27258    return result;
27259  }
27260
27261  function handleCallback(value, resolver, callback) {
27262    var callbackOutput = null;
27263    try {
27264      if (isFunction(callback)) callbackOutput = callback();
27265    } catch (e) {
27266      return reject(e);
27267    }
27268    if (isPromiseLike(callbackOutput)) {
27269      return callbackOutput.then(function() {
27270        return resolver(value);
27271      }, reject);
27272    } else {
27273      return resolver(value);
27274    }
27275  }
27276
27277  /**
27278   * @ngdoc method
27279   * @name $q#when
27280   * @kind function
27281   *
27282   * @description
27283   * Wraps an object that might be a value or a (3rd party) then-able promise into a $q promise.
27284   * This is useful when you are dealing with an object that might or might not be a promise, or if
27285   * the promise comes from a source that can't be trusted.
27286   *
27287   * @param {*} value Value or a promise
27288   * @param {Function=} successCallback
27289   * @param {Function=} errorCallback
27290   * @param {Function=} progressCallback
27291   * @returns {Promise} Returns a promise of the passed value or promise
27292   */
27293
27294
27295  function when(value, callback, errback, progressBack) {
27296    var result = new Promise();
27297    resolvePromise(result, value);
27298    return result.then(callback, errback, progressBack);
27299  }
27300
27301  /**
27302   * @ngdoc method
27303   * @name $q#resolve
27304   * @kind function
27305   *
27306   * @description
27307   * Alias of {@link ng.$q#when when} to maintain naming consistency with ES6.
27308   *
27309   * @param {*} value Value or a promise
27310   * @param {Function=} successCallback
27311   * @param {Function=} errorCallback
27312   * @param {Function=} progressCallback
27313   * @returns {Promise} Returns a promise of the passed value or promise
27314   */
27315  var resolve = when;
27316
27317  /**
27318   * @ngdoc method
27319   * @name $q#all
27320   * @kind function
27321   *
27322   * @description
27323   * Combines multiple promises into a single promise that is resolved when all of the input
27324   * promises are resolved.
27325   *
27326   * @param {Array.<Promise>|Object.<Promise>} promises An array or hash of promises.
27327   * @returns {Promise} Returns a single promise that will be resolved with an array/hash of values,
27328   *   each value corresponding to the promise at the same index/key in the `promises` array/hash.
27329   *   If any of the promises is resolved with a rejection, this resulting promise will be rejected
27330   *   with the same rejection value.
27331   */
27332
27333  function all(promises) {
27334    var result = new Promise(),
27335        counter = 0,
27336        results = isArray(promises) ? [] : {};
27337
27338    forEach(promises, function(promise, key) {
27339      counter++;
27340      when(promise).then(function(value) {
27341        results[key] = value;
27342        if (!(--counter)) resolvePromise(result, results);
27343      }, function(reason) {
27344        rejectPromise(result, reason);
27345      });
27346    });
27347
27348    if (counter === 0) {
27349      resolvePromise(result, results);
27350    }
27351
27352    return result;
27353  }
27354
27355  /**
27356   * @ngdoc method
27357   * @name $q#race
27358   * @kind function
27359   *
27360   * @description
27361   * Returns a promise that resolves or rejects as soon as one of those promises
27362   * resolves or rejects, with the value or reason from that promise.
27363   *
27364   * @param {Array.<Promise>|Object.<Promise>} promises An array or hash of promises.
27365   * @returns {Promise} a promise that resolves or rejects as soon as one of the `promises`
27366   * resolves or rejects, with the value or reason from that promise.
27367   */
27368
27369  function race(promises) {
27370    var deferred = defer();
27371
27372    forEach(promises, function(promise) {
27373      when(promise).then(deferred.resolve, deferred.reject);
27374    });
27375
27376    return deferred.promise;
27377  }
27378
27379  function $Q(resolver) {
27380    if (!isFunction(resolver)) {
27381      throw $qMinErr('norslvr', 'Expected resolverFn, got \'{0}\'', resolver);
27382    }
27383
27384    var promise = new Promise();
27385
27386    function resolveFn(value) {
27387      resolvePromise(promise, value);
27388    }
27389
27390    function rejectFn(reason) {
27391      rejectPromise(promise, reason);
27392    }
27393
27394    resolver(resolveFn, rejectFn);
27395
27396    return promise;
27397  }
27398
27399  // Let's make the instanceof operator work for promises, so that
27400  // `new $q(fn) instanceof $q` would evaluate to true.
27401  $Q.prototype = Promise.prototype;
27402
27403  $Q.defer = defer;
27404  $Q.reject = reject;
27405  $Q.when = when;
27406  $Q.resolve = resolve;
27407  $Q.all = all;
27408  $Q.race = race;
27409
27410  return $Q;
27411}
27412
27413/** @this */
27414function $$RAFProvider() { //rAF
27415  this.$get = ['$window', '$timeout', function($window, $timeout) {
27416    var requestAnimationFrame = $window.requestAnimationFrame ||
27417                                $window.webkitRequestAnimationFrame;
27418
27419    var cancelAnimationFrame = $window.cancelAnimationFrame ||
27420                               $window.webkitCancelAnimationFrame ||
27421                               $window.webkitCancelRequestAnimationFrame;
27422
27423    var rafSupported = !!requestAnimationFrame;
27424    var raf = rafSupported
27425      ? function(fn) {
27426          var id = requestAnimationFrame(fn);
27427          return function() {
27428            cancelAnimationFrame(id);
27429          };
27430        }
27431      : function(fn) {
27432          var timer = $timeout(fn, 16.66, false); // 1000 / 60 = 16.666
27433          return function() {
27434            $timeout.cancel(timer);
27435          };
27436        };
27437
27438    raf.supported = rafSupported;
27439
27440    return raf;
27441  }];
27442}
27443
27444/**
27445 * DESIGN NOTES
27446 *
27447 * The design decisions behind the scope are heavily favored for speed and memory consumption.
27448 *
27449 * The typical use of scope is to watch the expressions, which most of the time return the same
27450 * value as last time so we optimize the operation.
27451 *
27452 * Closures construction is expensive in terms of speed as well as memory:
27453 *   - No closures, instead use prototypical inheritance for API
27454 *   - Internal state needs to be stored on scope directly, which means that private state is
27455 *     exposed as $$____ properties
27456 *
27457 * Loop operations are optimized by using while(count--) { ... }
27458 *   - This means that in order to keep the same order of execution as addition we have to add
27459 *     items to the array at the beginning (unshift) instead of at the end (push)
27460 *
27461 * Child scopes are created and removed often
27462 *   - Using an array would be slow since inserts in the middle are expensive; so we use linked lists
27463 *
27464 * There are fewer watches than observers. This is why you don't want the observer to be implemented
27465 * in the same way as watch. Watch requires return of the initialization function which is expensive
27466 * to construct.
27467 */
27468
27469
27470/**
27471 * @ngdoc provider
27472 * @name $rootScopeProvider
27473 * @description
27474 *
27475 * Provider for the $rootScope service.
27476 */
27477
27478/**
27479 * @ngdoc method
27480 * @name $rootScopeProvider#digestTtl
27481 * @description
27482 *
27483 * Sets the number of `$digest` iterations the scope should attempt to execute before giving up and
27484 * assuming that the model is unstable.
27485 *
27486 * The current default is 10 iterations.
27487 *
27488 * In complex applications it's possible that the dependencies between `$watch`s will result in
27489 * several digest iterations. However if an application needs more than the default 10 digest
27490 * iterations for its model to stabilize then you should investigate what is causing the model to
27491 * continuously change during the digest.
27492 *
27493 * Increasing the TTL could have performance implications, so you should not change it without
27494 * proper justification.
27495 *
27496 * @param {number} limit The number of digest iterations.
27497 */
27498
27499
27500/**
27501 * @ngdoc service
27502 * @name $rootScope
27503 * @this
27504 *
27505 * @description
27506 *
27507 * Every application has a single root {@link ng.$rootScope.Scope scope}.
27508 * All other scopes are descendant scopes of the root scope. Scopes provide separation
27509 * between the model and the view, via a mechanism for watching the model for changes.
27510 * They also provide event emission/broadcast and subscription facility. See the
27511 * {@link guide/scope developer guide on scopes}.
27512 */
27513function $RootScopeProvider() {
27514  var TTL = 10;
27515  var $rootScopeMinErr = minErr('$rootScope');
27516  var lastDirtyWatch = null;
27517  var applyAsyncId = null;
27518
27519  this.digestTtl = function(value) {
27520    if (arguments.length) {
27521      TTL = value;
27522    }
27523    return TTL;
27524  };
27525
27526  function createChildScopeClass(parent) {
27527    function ChildScope() {
vendor: 11,072 bytes, lines 27528-27788
27528      this.$$watchers = this.$$nextSibling =
27529          this.$$childHead = this.$$childTail = null;
27530      this.$$listeners = {};
27531      this.$$listenerCount = {};
27532      this.$$watchersCount = 0;
27533      this.$id = nextUid();
27534      this.$$ChildScope = null;
27535    }
27536    ChildScope.prototype = parent;
27537    return ChildScope;
27538  }
27539
27540  this.$get = ['$exceptionHandler', '$parse', '$browser',
27541      function($exceptionHandler, $parse, $browser) {
27542
27543    function destroyChildScope($event) {
27544        $event.currentScope.$$destroyed = true;
27545    }
27546
27547    function cleanUpScope($scope) {
27548
27549      // Support: IE 9 only
27550      if (msie === 9) {
27551        // There is a memory leak in IE9 if all child scopes are not disconnected
27552        // completely when a scope is destroyed. So this code will recurse up through
27553        // all this scopes children
27554        //
27555        // See issue https://github.com/angular/angular.js/issues/10706
27556        if ($scope.$$childHead) {
27557          cleanUpScope($scope.$$childHead);
27558        }
27559        if ($scope.$$nextSibling) {
27560          cleanUpScope($scope.$$nextSibling);
27561        }
27562      }
27563
27564      // The code below works around IE9 and V8's memory leaks
27565      //
27566      // See:
27567      // - https://code.google.com/p/v8/issues/detail?id=2073#c26
27568      // - https://github.com/angular/angular.js/issues/6794#issuecomment-38648909
27569      // - https://github.com/angular/angular.js/issues/1313#issuecomment-10378451
27570
27571      $scope.$parent = $scope.$$nextSibling = $scope.$$prevSibling = $scope.$$childHead =
27572          $scope.$$childTail = $scope.$root = $scope.$$watchers = null;
27573    }
27574
27575    /**
27576     * @ngdoc type
27577     * @name $rootScope.Scope
27578     *
27579     * @description
27580     * A root scope can be retrieved using the {@link ng.$rootScope $rootScope} key from the
27581     * {@link auto.$injector $injector}. Child scopes are created using the
27582     * {@link ng.$rootScope.Scope#$new $new()} method. (Most scopes are created automatically when
27583     * compiled HTML template is executed.) See also the {@link guide/scope Scopes guide} for
27584     * an in-depth introduction and usage examples.
27585     *
27586     *
27587     * # Inheritance
27588     * A scope can inherit from a parent scope, as in this example:
27589     * ```js
27590         var parent = $rootScope;
27591         var child = parent.$new();
27592
27593         parent.salutation = "Hello";
27594         expect(child.salutation).toEqual('Hello');
27595
27596         child.salutation = "Welcome";
27597         expect(child.salutation).toEqual('Welcome');
27598         expect(parent.salutation).toEqual('Hello');
27599     * ```
27600     *
27601     * When interacting with `Scope` in tests, additional helper methods are available on the
27602     * instances of `Scope` type. See {@link ngMock.$rootScope.Scope ngMock Scope} for additional
27603     * details.
27604     *
27605     *
27606     * @param {Object.<string, function()>=} providers Map of service factory which need to be
27607     *                                       provided for the current scope. Defaults to {@link ng}.
27608     * @param {Object.<string, *>=} instanceCache Provides pre-instantiated services which should
27609     *                              append/override services provided by `providers`. This is handy
27610     *                              when unit-testing and having the need to override a default
27611     *                              service.
27612     * @returns {Object} Newly created scope.
27613     *
27614     */
27615    function Scope() {
27616      this.$id = nextUid();
27617      this.$$phase = this.$parent = this.$$watchers =
27618                     this.$$nextSibling = this.$$prevSibling =
27619                     this.$$childHead = this.$$childTail = null;
27620      this.$root = this;
27621      this.$$destroyed = false;
27622      this.$$listeners = {};
27623      this.$$listenerCount = {};
27624      this.$$watchersCount = 0;
27625      this.$$isolateBindings = null;
27626    }
27627
27628    /**
27629     * @ngdoc property
27630     * @name $rootScope.Scope#$id
27631     *
27632     * @description
27633     * Unique scope ID (monotonically increasing) useful for debugging.
27634     */
27635
27636     /**
27637      * @ngdoc property
27638      * @name $rootScope.Scope#$parent
27639      *
27640      * @description
27641      * Reference to the parent scope.
27642      */
27643
27644      /**
27645       * @ngdoc property
27646       * @name $rootScope.Scope#$root
27647       *
27648       * @description
27649       * Reference to the root scope.
27650       */
27651
27652    Scope.prototype = {
27653      constructor: Scope,
27654      /**
27655       * @ngdoc method
27656       * @name $rootScope.Scope#$new
27657       * @kind function
27658       *
27659       * @description
27660       * Creates a new child {@link ng.$rootScope.Scope scope}.
27661       *
27662       * The parent scope will propagate the {@link ng.$rootScope.Scope#$digest $digest()} event.
27663       * The scope can be removed from the scope hierarchy using {@link ng.$rootScope.Scope#$destroy $destroy()}.
27664       *
27665       * {@link ng.$rootScope.Scope#$destroy $destroy()} must be called on a scope when it is
27666       * desired for the scope and its child scopes to be permanently detached from the parent and
27667       * thus stop participating in model change detection and listener notification by invoking.
27668       *
27669       * @param {boolean} isolate If true, then the scope does not prototypically inherit from the
27670       *         parent scope. The scope is isolated, as it can not see parent scope properties.
27671       *         When creating widgets, it is useful for the widget to not accidentally read parent
27672       *         state.
27673       *
27674       * @param {Scope} [parent=this] The {@link ng.$rootScope.Scope `Scope`} that will be the `$parent`
27675       *                              of the newly created scope. Defaults to `this` scope if not provided.
27676       *                              This is used when creating a transclude scope to correctly place it
27677       *                              in the scope hierarchy while maintaining the correct prototypical
27678       *                              inheritance.
27679       *
27680       * @returns {Object} The newly created child scope.
27681       *
27682       */
27683      $new: function(isolate, parent) {
27684        var child;
27685
27686        parent = parent || this;
27687
27688        if (isolate) {
27689          child = new Scope();
27690          child.$root = this.$root;
27691        } else {
27692          // Only create a child scope class if somebody asks for one,
27693          // but cache it to allow the VM to optimize lookups.
27694          if (!this.$$ChildScope) {
27695            this.$$ChildScope = createChildScopeClass(this);
27696          }
27697          child = new this.$$ChildScope();
27698        }
27699        child.$parent = parent;
27700        child.$$prevSibling = parent.$$childTail;
27701        if (parent.$$childHead) {
27702          parent.$$childTail.$$nextSibling = child;
27703          parent.$$childTail = child;
27704        } else {
27705          parent.$$childHead = parent.$$childTail = child;
27706        }
27707
27708        // When the new scope is not isolated or we inherit from `this`, and
27709        // the parent scope is destroyed, the property `$$destroyed` is inherited
27710        // prototypically. In all other cases, this property needs to be set
27711        // when the parent scope is destroyed.
27712        // The listener needs to be added after the parent is set
27713        if (isolate || parent !== this) child.$on('$destroy', destroyChildScope);
27714
27715        return child;
27716      },
27717
27718      /**
27719       * @ngdoc method
27720       * @name $rootScope.Scope#$watch
27721       * @kind function
27722       *
27723       * @description
27724       * Registers a `listener` callback to be executed whenever the `watchExpression` changes.
27725       *
27726       * - The `watchExpression` is called on every call to {@link ng.$rootScope.Scope#$digest
27727       *   $digest()} and should return the value that will be watched. (`watchExpression` should not change
27728       *   its value when executed multiple times with the same input because it may be executed multiple
27729       *   times by {@link ng.$rootScope.Scope#$digest $digest()}. That is, `watchExpression` should be
27730       *   [idempotent](http://en.wikipedia.org/wiki/Idempotence).)
27731       * - The `listener` is called only when the value from the current `watchExpression` and the
27732       *   previous call to `watchExpression` are not equal (with the exception of the initial run,
27733       *   see below). Inequality is determined according to reference inequality,
27734       *   [strict comparison](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Comparison_Operators)
27735       *    via the `!==` Javascript operator, unless `objectEquality == true`
27736       *   (see next point)
27737       * - When `objectEquality == true`, inequality of the `watchExpression` is determined
27738       *   according to the {@link angular.equals} function. To save the value of the object for
27739       *   later comparison, the {@link angular.copy} function is used. This therefore means that
27740       *   watching complex objects will have adverse memory and performance implications.
27741       * - This should not be used to watch for changes in objects that are
27742       *   or contain [File](https://developer.mozilla.org/docs/Web/API/File) objects due to limitations with {@link angular.copy `angular.copy`}.
27743       * - The watch `listener` may change the model, which may trigger other `listener`s to fire.
27744       *   This is achieved by rerunning the watchers until no changes are detected. The rerun
27745       *   iteration limit is 10 to prevent an infinite loop deadlock.
27746       *
27747       *
27748       * If you want to be notified whenever {@link ng.$rootScope.Scope#$digest $digest} is called,
27749       * you can register a `watchExpression` function with no `listener`. (Be prepared for
27750       * multiple calls to your `watchExpression` because it will execute multiple times in a
27751       * single {@link ng.$rootScope.Scope#$digest $digest} cycle if a change is detected.)
27752       *
27753       * After a watcher is registered with the scope, the `listener` fn is called asynchronously
27754       * (via {@link ng.$rootScope.Scope#$evalAsync $evalAsync}) to initialize the
27755       * watcher. In rare cases, this is undesirable because the listener is called when the result
27756       * of `watchExpression` didn't change. To detect this scenario within the `listener` fn, you
27757       * can compare the `newVal` and `oldVal`. If these two values are identical (`===`) then the
27758       * listener was called due to initialization.
27759       *
27760       *
27761       *
27762       * # Example
27763       * ```js
27764           // let's assume that scope was dependency injected as the $rootScope
27765           var scope = $rootScope;
27766           scope.name = 'misko';
27767           scope.counter = 0;
27768
27769           expect(scope.counter).toEqual(0);
27770           scope.$watch('name', function(newValue, oldValue) {
27771             scope.counter = scope.counter + 1;
27772           });
27773           expect(scope.counter).toEqual(0);
27774
27775           scope.$digest();
27776           // the listener is always called during the first $digest loop after it was registered
27777           expect(scope.counter).toEqual(1);
27778
27779           scope.$digest();
27780           // but now it will not be called unless the value changes
27781           expect(scope.counter).toEqual(1);
27782
27783           scope.name = 'adam';
27784           scope.$digest();
27785           expect(scope.counter).toEqual(2);
27786
27787
27788
27789           // Using a function as a watchExpression
27790           var food;
27791           scope.foodCounter = 0;
27792           expect(scope.foodCounter).toEqual(0);
27793           scope.$watch(
27794             // This function returns the value being watched. It is called for each turn of the $digest loop
27795             function() { return food; },
27796             // This is the change listener, called when the value returned from the above function changes
27797             function(newValue, oldValue) {
27798               if ( newValue !== oldValue ) {
27799                 // Only increment the counter if the value changed
27800                 scope.foodCounter = scope.foodCounter + 1;
27801               }
27802             }
27803           );
27804           // No digest has been run so the counter will be zero
27805           expect(scope.foodCounter).toEqual(0);
27806
27807           // Run the digest but since food has not changed count will still be zero
27808           scope.$digest();
27809           expect(scope.foodCounter).toEqual(0);
27810
27811           // Update food and run digest.  Now the counter will increment
27812           food = 'cheeseburger';
27813           scope.$digest();
27814           expect(scope.foodCounter).toEqual(1);
27815
27816       * ```
27817       *
27818       *
27819       *
27820       * @param {(function()|string)} watchExpression Expression that is evaluated on each
27821       *    {@link ng.$rootScope.Scope#$digest $digest} cycle. A change in the return value triggers
27822       *    a call to the `listener`.
27823       *
27824       *    - `string`: Evaluated as {@link guide/expression expression}
27825       *    - `function(scope)`: called with current `scope` as a parameter.
27826       * @param {function(newVal, oldVal, scope)} listener Callback called whenever the value
27827       *    of `watchExpression` changes.
27828       *
27829       *    - `newVal` contains the current value of the `watchExpression`
27830       *    - `oldVal` contains the previous value of the `watchExpression`
27831       *    - `scope` refers to the current scope
27832       * @param {boolean=} [objectEquality=false] Compare for object equality using {@link angular.equals} instead of
27833       *     comparing for reference equality.
27834       * @returns {function()} Returns a deregistration function for this listener.
27835       */
27836      $watch: function(watchExp, listener, objectEquality, prettyPrintExpression) {
27837        var get = $parse(watchExp);
27838
27839        if (get.$$watchDelegate) {
27840          return get.$$watchDelegate(this, listener, objectEquality, get, watchExp);
27841        }
27842        var scope = this,
27843            array = scope.$$watchers,
27844            watcher = {
27845              fn: listener,
27846              last: initWatchVal,
27847              get: get,
27848              exp: prettyPrintExpression || watchExp,
27849              eq: !!objectEquality
27850            };
27851
27852        lastDirtyWatch = null;
27853
27854        if (!isFunction(listener)) {
27855          watcher.fn = noop;
27856        }
27857
27858        if (!array) {
27859          array = scope.$$watchers = [];
27860          array.$$digestWatchIndex = -1;
27861        }
27862        // we use unshift since we use a while loop in $digest for speed.
27863        // the while loop reads in reverse order.
27864        array.unshift(watcher);
27865        array.$$digestWatchIndex++;
27866        incrementWatchersCount(this, 1);
27867
27868        return function deregisterWatch() {
27869          var index = arrayRemove(array, watcher);
27870          if (index >= 0) {
27871            incrementWatchersCount(scope, -1);
27872            if (index < array.$$digestWatchIndex) {
27873              array.$$digestWatchIndex--;
27874            }
27875          }
27876          lastDirtyWatch = null;
27877        };
27878      },
27879
27880      /**
27881       * @ngdoc method
27882       * @name $rootScope.Scope#$watchGroup
27883       * @kind function
27884       *
27885       * @description
27886       * A variant of {@link ng.$rootScope.Scope#$watch $watch()} where it watches an array of `watchExpressions`.
27887       * If any one expression in the collection changes the `listener` is executed.
27888       *
27889       * - The items in the `watchExpressions` array are observed via the standard `$watch` operation. Their return
27890       *   values are examined for changes on every call to `$digest`.
27891       * - The `listener` is called whenever any expression in the `watchExpressions` array changes.
27892       *
27893       * @param {Array.<string|Function(scope)>} watchExpressions Array of expressions that will be individually
27894       * watched using {@link ng.$rootScope.Scope#$watch $watch()}
27895       *
27896       * @param {function(newValues, oldValues, scope)} listener Callback called whenever the return value of any
27897       *    expression in `watchExpressions` changes
27898       *    The `newValues` array contains the current values of the `watchExpressions`, with the indexes matching
27899       *    those of `watchExpression`
27900       *    and the `oldValues` array contains the previous values of the `watchExpressions`, with the indexes matching
27901       *    those of `watchExpression`
27902       *    The `scope` refers to the current scope.
27903       * @returns {function()} Returns a de-registration function for all listeners.
27904       */
27905      $watchGroup: function(watchExpressions, listener) {
27906        var oldValues = new Array(watchExpressions.length);
27907        var newValues = new Array(watchExpressions.length);
27908        var deregisterFns = [];
27909        var self = this;
27910        var changeReactionScheduled = false;
vendor: 4,272 bytes, lines 27911-28020
27911        var firstRun = true;
27912
27913        if (!watchExpressions.length) {
27914          // No expressions means we call the listener ASAP
27915          var shouldCall = true;
27916          self.$evalAsync(function() {
27917            if (shouldCall) listener(newValues, newValues, self);
27918          });
27919          return function deregisterWatchGroup() {
27920            shouldCall = false;
27921          };
27922        }
27923
27924        if (watchExpressions.length === 1) {
27925          // Special case size of one
27926          return this.$watch(watchExpressions[0], function watchGroupAction(value, oldValue, scope) {
27927            newValues[0] = value;
27928            oldValues[0] = oldValue;
27929            listener(newValues, (value === oldValue) ? newValues : oldValues, scope);
27930          });
27931        }
27932
27933        forEach(watchExpressions, function(expr, i) {
27934          var unwatchFn = self.$watch(expr, function watchGroupSubAction(value, oldValue) {
27935            newValues[i] = value;
27936            oldValues[i] = oldValue;
27937            if (!changeReactionScheduled) {
27938              changeReactionScheduled = true;
27939              self.$evalAsync(watchGroupAction);
27940            }
27941          });
27942          deregisterFns.push(unwatchFn);
27943        });
27944
27945        function watchGroupAction() {
27946          changeReactionScheduled = false;
27947
27948          if (firstRun) {
27949            firstRun = false;
27950            listener(newValues, newValues, self);
27951          } else {
27952            listener(newValues, oldValues, self);
27953          }
27954        }
27955
27956        return function deregisterWatchGroup() {
27957          while (deregisterFns.length) {
27958            deregisterFns.shift()();
27959          }
27960        };
27961      },
27962
27963
27964      /**
27965       * @ngdoc method
27966       * @name $rootScope.Scope#$watchCollection
27967       * @kind function
27968       *
27969       * @description
27970       * Shallow watches the properties of an object and fires whenever any of the properties change
27971       * (for arrays, this implies watching the array items; for object maps, this implies watching
27972       * the properties). If a change is detected, the `listener` callback is fired.
27973       *
27974       * - The `obj` collection is observed via standard $watch operation and is examined on every
27975       *   call to $digest() to see if any items have been added, removed, or moved.
27976       * - The `listener` is called whenever anything within the `obj` has changed. Examples include
27977       *   adding, removing, and moving items belonging to an object or array.
27978       *
27979       *
27980       * # Example
27981       * ```js
27982          $scope.names = ['igor', 'matias', 'misko', 'james'];
27983          $scope.dataCount = 4;
27984
27985          $scope.$watchCollection('names', function(newNames, oldNames) {
27986            $scope.dataCount = newNames.length;
27987          });
27988
27989          expect($scope.dataCount).toEqual(4);
27990          $scope.$digest();
27991
27992          //still at 4 ... no changes
27993          expect($scope.dataCount).toEqual(4);
27994
27995          $scope.names.pop();
27996          $scope.$digest();
27997
27998          //now there's been a change
27999          expect($scope.dataCount).toEqual(3);
28000       * ```
28001       *
28002       *
28003       * @param {string|function(scope)} obj Evaluated as {@link guide/expression expression}. The
28004       *    expression value should evaluate to an object or an array which is observed on each
28005       *    {@link ng.$rootScope.Scope#$digest $digest} cycle. Any shallow change within the
28006       *    collection will trigger a call to the `listener`.
28007       *
28008       * @param {function(newCollection, oldCollection, scope)} listener a callback function called
28009       *    when a change is detected.
28010       *    - The `newCollection` object is the newly modified data obtained from the `obj` expression
28011       *    - The `oldCollection` object is a copy of the former collection data.
28012       *      Due to performance considerations, the`oldCollection` value is computed only if the
28013       *      `listener` function declares two or more arguments.
28014       *    - The `scope` argument refers to the current scope.
28015       *
28016       * @returns {function()} Returns a de-registration function for this listener. When the
28017       *    de-registration function is executed, the internal watch operation is terminated.
28018       */
28019      $watchCollection: function(obj, listener) {
28020        $watchCollectionInterceptor.$stateful = tru
vendor: 6,149 bytes, lines 28020-28178
28020e;
28021
28022        var self = this;
28023        // the current value, updated on each dirty-check run
28024        var newValue;
28025        // a shallow copy of the newValue from the last dirty-check run,
28026        // updated to match newValue during dirty-check run
28027        var oldValue;
28028        // a shallow copy of the newValue from when the last change happened
28029        var veryOldValue;
28030        // only track veryOldValue if the listener is asking for it
28031        var trackVeryOldValue = (listener.length > 1);
28032        var changeDetected = 0;
28033        var changeDetector = $parse(obj, $watchCollectionInterceptor);
28034        var internalArray = [];
28035        var internalObject = {};
28036        var initRun = true;
28037        var oldLength = 0;
28038
28039        function $watchCollectionInterceptor(_value) {
28040          newValue = _value;
28041          var newLength, key, bothNaN, newItem, oldItem;
28042
28043          // If the new value is undefined, then return undefined as the watch may be a one-time watch
28044          if (isUndefined(newValue)) return;
28045
28046          if (!isObject(newValue)) { // if primitive
28047            if (oldValue !== newValue) {
28048              oldValue = newValue;
28049              changeDetected++;
28050            }
28051          } else if (isArrayLike(newValue)) {
28052            if (oldValue !== internalArray) {
28053              // we are transitioning from something which was not an array into array.
28054              oldValue = internalArray;
28055              oldLength = oldValue.length = 0;
28056              changeDetected++;
28057            }
28058
28059            newLength = newValue.length;
28060
28061            if (oldLength !== newLength) {
28062              // if lengths do not match we need to trigger change notification
28063              changeDetected++;
28064              oldValue.length = oldLength = newLength;
28065            }
28066            // copy the items to oldValue and look for changes.
28067            for (var i = 0; i < newLength; i++) {
28068              oldItem = oldValue[i];
28069              newItem = newValue[i];
28070
28071              // eslint-disable-next-line no-self-compare
28072              bothNaN = (oldItem !== oldItem) && (newItem !== newItem);
28073              if (!bothNaN && (oldItem !== newItem)) {
28074                changeDetected++;
28075                oldValue[i] = newItem;
28076              }
28077            }
28078          } else {
28079            if (oldValue !== internalObject) {
28080              // we are transitioning from something which was not an object into object.
28081              oldValue = internalObject = {};
28082              oldLength = 0;
28083              changeDetected++;
28084            }
28085            // copy the items to oldValue and look for changes.
28086            newLength = 0;
28087            for (key in newValue) {
28088              if (hasOwnProperty.call(newValue, key)) {
28089                newLength++;
28090                newItem = newValue[key];
28091                oldItem = oldValue[key];
28092
28093                if (key in oldValue) {
28094                  // eslint-disable-next-line no-self-compare
28095                  bothNaN = (oldItem !== oldItem) && (newItem !== newItem);
28096                  if (!bothNaN && (oldItem !== newItem)) {
28097                    changeDetected++;
28098                    oldValue[key] = newItem;
28099                  }
28100                } else {
28101                  oldLength++;
28102                  oldValue[key] = newItem;
28103                  changeDetected++;
28104                }
28105              }
28106            }
28107            if (oldLength > newLength) {
28108              // we used to have more keys, need to find them and destroy them.
28109              changeDetected++;
28110              for (key in oldValue) {
28111                if (!hasOwnProperty.call(newValue, key)) {
28112                  oldLength--;
28113                  delete oldValue[key];
28114                }
28115              }
28116            }
28117          }
28118          return changeDetected;
28119        }
28120
28121        function $watchCollectionAction() {
28122          if (initRun) {
28123            initRun = false;
28124            listener(newValue, newValue, self);
28125          } else {
28126            listener(newValue, veryOldValue, self);
28127          }
28128
28129          // make a copy for the next time a collection is changed
28130          if (trackVeryOldValue) {
28131            if (!isObject(newValue)) {
28132              //primitive
28133              veryOldValue = newValue;
28134            } else if (isArrayLike(newValue)) {
28135              veryOldValue = new Array(newValue.length);
28136              for (var i = 0; i < newValue.length; i++) {
28137                veryOldValue[i] = newValue[i];
28138              }
28139            } else { // if object
28140              veryOldValue = {};
28141              for (var key in newValue) {
28142                if (hasOwnProperty.call(newValue, key)) {
28143                  veryOldValue[key] = newValue[key];
28144                }
28145              }
28146            }
28147          }
28148        }
28149
28150        return this.$watch(changeDetector, $watchCollectionAction);
28151      },
28152
28153      /**
28154       * @ngdoc method
28155       * @name $rootScope.Scope#$digest
28156       * @kind function
28157       *
28158       * @description
28159       * Processes all of the {@link ng.$rootScope.Scope#$watch watchers} of the current scope and
28160       * its children. Because a {@link ng.$rootScope.Scope#$watch watcher}'s listener can change
28161       * the model, the `$digest()` keeps calling the {@link ng.$rootScope.Scope#$watch watchers}
28162       * until no more listeners are firing. This means that it is possible to get into an infinite
28163       * loop. This function will throw `'Maximum iteration limit exceeded.'` if the number of
28164       * iterations exceeds 10.
28165       *
28166       * Usually, you don't call `$digest()` directly in
28167       * {@link ng.directive:ngController controllers} or in
28168       * {@link ng.$compileProvider#directive directives}.
28169       * Instead, you should call {@link ng.$rootScope.Scope#$apply $apply()} (typically from within
28170       * a {@link ng.$compileProvider#directive directive}), which will force a `$digest()`.
28171       *
28172       * If you want to be notified whenever `$digest()` is called,
28173       * you can register a `watchExpression` function with
28174       * {@link ng.$rootScope.Scope#$watch $watch()} with no `listener`.
28175       *
28176       * In unit tests, you may need to call `$digest()` to simulate the scope life cycle.
28177       *
28178       * 
vendor: 9,120 bytes, lines 28178-28401
28178# Example
28179       * ```js
28180           var scope = ...;
28181           scope.name = 'misko';
28182           scope.counter = 0;
28183
28184           expect(scope.counter).toEqual(0);
28185           scope.$watch('name', function(newValue, oldValue) {
28186             scope.counter = scope.counter + 1;
28187           });
28188           expect(scope.counter).toEqual(0);
28189
28190           scope.$digest();
28191           // the listener is always called during the first $digest loop after it was registered
28192           expect(scope.counter).toEqual(1);
28193
28194           scope.$digest();
28195           // but now it will not be called unless the value changes
28196           expect(scope.counter).toEqual(1);
28197
28198           scope.name = 'adam';
28199           scope.$digest();
28200           expect(scope.counter).toEqual(2);
28201       * ```
28202       *
28203       */
28204      $digest: function() {
28205        var watch, value, last, fn, get,
28206            watchers,
28207            dirty, ttl = TTL,
28208            next, current, target = this,
28209            watchLog = [],
28210            logIdx, asyncTask;
28211
28212        beginPhase('$digest');
28213        // Check for changes to browser url that happened in sync before the call to $digest
28214        $browser.$$checkUrlChange();
28215
28216        if (this === $rootScope && applyAsyncId !== null) {
28217          // If this is the root scope, and $applyAsync has scheduled a deferred $apply(), then
28218          // cancel the scheduled $apply and flush the queue of expressions to be evaluated.
28219          $browser.defer.cancel(applyAsyncId);
28220          flushApplyAsync();
28221        }
28222
28223        lastDirtyWatch = null;
28224
28225        do { // "while dirty" loop
28226          dirty = false;
28227          current = target;
28228
28229          // It's safe for asyncQueuePosition to be a local variable here because this loop can't
28230          // be reentered recursively. Calling $digest from a function passed to $evalAsync would
28231          // lead to a '$digest already in progress' error.
28232          for (var asyncQueuePosition = 0; asyncQueuePosition < asyncQueue.length; asyncQueuePosition++) {
28233            try {
28234              asyncTask = asyncQueue[asyncQueuePosition];
28235              fn = asyncTask.fn;
28236              fn(asyncTask.scope, asyncTask.locals);
28237            } catch (e) {
28238              $exceptionHandler(e);
28239            }
28240            lastDirtyWatch = null;
28241          }
28242          asyncQueue.length = 0;
28243
28244          traverseScopesLoop:
28245          do { // "traverse the scopes" loop
28246            if ((watchers = current.$$watchers)) {
28247              // process our watches
28248              watchers.$$digestWatchIndex = watchers.length;
28249              while (watchers.$$digestWatchIndex--) {
28250                try {
28251                  watch = watchers[watchers.$$digestWatchIndex];
28252                  // Most common watches are on primitives, in which case we can short
28253                  // circuit it with === operator, only when === fails do we use .equals
28254                  if (watch) {
28255                    get = watch.get;
28256                    if ((value = get(current)) !== (last = watch.last) &&
28257                        !(watch.eq
28258                            ? equals(value, last)
28259                            : (isNumberNaN(value) && isNumberNaN(last)))) {
28260                      dirty = true;
28261                      lastDirtyWatch = watch;
28262                      watch.last = watch.eq ? copy(value, null) : value;
28263                      fn = watch.fn;
28264                      fn(value, ((last === initWatchVal) ? value : last), current);
28265                      if (ttl < 5) {
28266                        logIdx = 4 - ttl;
28267                        if (!watchLog[logIdx]) watchLog[logIdx] = [];
28268                        watchLog[logIdx].push({
28269                          msg: isFunction(watch.exp) ? 'fn: ' + (watch.exp.name || watch.exp.toString()) : watch.exp,
28270                          newVal: value,
28271                          oldVal: last
28272                        });
28273                      }
28274                    } else if (watch === lastDirtyWatch) {
28275                      // If the most recently dirty watcher is now clean, short circuit since the remaining watchers
28276                      // have already been tested.
28277                      dirty = false;
28278                      break traverseScopesLoop;
28279                    }
28280                  }
28281                } catch (e) {
28282                  $exceptionHandler(e);
28283                }
28284              }
28285            }
28286
28287            // Insanity Warning: scope depth-first traversal
28288            // yes, this code is a bit crazy, but it works and we have tests to prove it!
28289            // this piece should be kept in sync with the traversal in $broadcast
28290            if (!(next = ((current.$$watchersCount && current.$$childHead) ||
28291                (current !== target && current.$$nextSibling)))) {
28292              while (current !== target && !(next = current.$$nextSibling)) {
28293                current = current.$parent;
28294              }
28295            }
28296          } while ((current = next));
28297
28298          // `break traverseScopesLoop;` takes us to here
28299
28300          if ((dirty || asyncQueue.length) && !(ttl--)) {
28301            clearPhase();
28302            throw $rootScopeMinErr('infdig',
28303                '{0} $digest() iterations reached. Aborting!\n' +
28304                'Watchers fired in the last 5 iterations: {1}',
28305                TTL, watchLog);
28306          }
28307
28308        } while (dirty || asyncQueue.length);
28309
28310        clearPhase();
28311
28312        // postDigestQueuePosition isn't local here because this loop can be reentered recursively.
28313        while (postDigestQueuePosition < postDigestQueue.length) {
28314          try {
28315            postDigestQueue[postDigestQueuePosition++]();
28316          } catch (e) {
28317            $exceptionHandler(e);
28318          }
28319        }
28320        postDigestQueue.length = postDigestQueuePosition = 0;
28321
28322        // Check for changes to browser url that happened during the $digest
28323        // (for which no event is fired; e.g. via `history.pushState()`)
28324        $browser.$$checkUrlChange();
28325      },
28326
28327
28328      /**
28329       * @ngdoc event
28330       * @name $rootScope.Scope#$destroy
28331       * @eventType broadcast on scope being destroyed
28332       *
28333       * @description
28334       * Broadcasted when a scope and its children are being destroyed.
28335       *
28336       * Note that, in AngularJS, there is also a `$destroy` jQuery event, which can be used to
28337       * clean up DOM bindings before an element is removed from the DOM.
28338       */
28339
28340      /**
28341       * @ngdoc method
28342       * @name $rootScope.Scope#$destroy
28343       * @kind function
28344       *
28345       * @description
28346       * Removes the current scope (and all of its children) from the parent scope. Removal implies
28347       * that calls to {@link ng.$rootScope.Scope#$digest $digest()} will no longer
28348       * propagate to the current scope and its children. Removal also implies that the current
28349       * scope is eligible for garbage collection.
28350       *
28351       * The `$destroy()` is usually used by directives such as
28352       * {@link ng.directive:ngRepeat ngRepeat} for managing the
28353       * unrolling of the loop.
28354       *
28355       * Just before a scope is destroyed, a `$destroy` event is broadcasted on this scope.
28356       * Application code can register a `$destroy` event handler that will give it a chance to
28357       * perform any necessary cleanup.
28358       *
28359       * Note that, in AngularJS, there is also a `$destroy` jQuery event, which can be used to
28360       * clean up DOM bindings before an element is removed from the DOM.
28361       */
28362      $destroy: function() {
28363        // We can't destroy a scope that has been already destroyed.
28364        if (this.$$destroyed) return;
28365        var parent = this.$parent;
28366
28367        this.$broadcast('$destroy');
28368        this.$$destroyed = true;
28369
28370        if (this === $rootScope) {
28371          //Remove handlers attached to window when $rootScope is removed
28372          $browser.$$applicationDestroyed();
28373        }
28374
28375        incrementWatchersCount(this, -this.$$watchersCount);
28376        for (var eventName in this.$$listenerCount) {
28377          decrementListenerCount(this, this.$$listenerCount[eventName], eventName);
28378        }
28379
28380        // sever all the references to parent scopes (after this cleanup, the current scope should
28381        // not be retained by any of our references and should be eligible for garbage collection)
28382        if (parent && parent.$$childHead === this) parent.$$childHead = this.$$nextSibling;
28383        if (parent && parent.$$childTail === this) parent.$$childTail = this.$$prevSibling;
28384        if (this.$$prevSibling) this.$$prevSibling.$$nextSibling = this.$$nextSibling;
28385        if (this.$$nextSibling) this.$$nextSibling.$$prevSibling = this.$$prevSibling;
28386
28387        // Disable listeners, watchers and apply/digest methods
28388        this.$destroy = this.$digest = this.$apply = this.$evalAsync = this.$applyAsync = noop;
28389        this.$on = this.$watch = this.$watchGroup = function() { return noop; };
28390        this.$$listeners = {};
28391
28392        // Disconnect the next sibling to prevent `cleanUpScope` destroying those too
28393        this.$$nextSibling = null;
28394        cleanUpScope(this);
28395      },
28396
28397      /**
28398       * @ngdoc method
28399       * @name $rootScope.Scope#$eval
28400       * @kind function
28401       *
28402       * @description
28403       * Executes the `expression` on the current scope and returns the result. Any exceptions in
28404       * the expression are propagated (uncaught). This is useful when evaluating Angular
28405       * expressions.
28406       *
28407       * # Example
28408       * ```js
28409           var scope = ng.$rootScope.Scope();
28410           scope.a = 1;
28411           scope.b = 2;
28412
28413           expect(scope.$eval('a+b')).toEqual(3);
28414           expect(scope.$eval(function(scope){ return scope.a + scope.b; })).toEqual(3);
28415       * ```
28416       *
28417       * @param {(string|function())=} expression An angular expression to be executed.
28418       *
28419       *    - `string`: execute using the rules as defined in  {@link guide/expression expression}.
28420       *    - `function(scope)`: execute the function with the current `scope` parameter.
28421       *
28422       * @param {(object)=} locals Local variables object, useful for overriding values in scope.
28423       * @returns {*} The result of evaluating the expression.
28424       */
28425      $eval: function(expr, locals) {
28426        return $parse(expr)(this, locals);
28427      },
28428
28429      /**
28430       * @ngdoc method
28431       * @name $rootScope.Scope#$evalAsync
28432       * @kind function
28433       *
28434       * @description
28435       * Executes the expression on the current scope at a later point in time.
28436       *
28437       * The `$evalAsync` makes no guarantees as to when the `expression` will be executed, only
28438       * that:
28439       *
28440       *   - it will execute after the function that scheduled the evaluation (preferably before DOM
28441       *     rendering).
28442       *   - at least one {@link ng.$rootScope.Scope#$digest $digest cycle} will be performed after
28443       *     `expression` execution.
28444       *
28445       * Any exceptions from the execution of the expression are forwarded to the
28446       * {@link ng.$exceptionHandler $exceptionHandler} service.
28447       *
28448       * __Note:__ if this function is called outside of a `$digest` cycle, a new `$digest` cycle
28449       * will be scheduled. However, it is encouraged to always call code that changes the model
28450       * from within an `$apply` call. That includes code evaluated via `$evalAsync`.
28451       *
28452       * @param {(string|function())=} expression An angular expression to be executed.
28453       *
28454       *    - `string`: execute using the rules as defined in {@link guide/expression expression}.
28455       *    - `function(scope)`: execute the function with the current `scope` parameter.
28456       *
28457       * @param {(object)=} locals Local variables object, useful for overriding values in scope.
28458       */
28459      $evalAsync: function(expr, locals) {
28460        // if we are outside of an $digest loop and this is the first time we are scheduling async
28461        // task also schedule async auto-flush
28462        if (!$rootScope.$$phase && !asyncQueue.length) {
28463          $browser.defer(function() {
28464            if (asyncQueue.length) {
28465              $rootScope.$digest();
28466            }
28467          });
28468        }
28469
28470        asyncQueue.push({scope: this, fn: $parse(expr), locals: locals});
28471      },
28472
28473      $$postDigest: function(fn) {
28474        postDigestQueue.push(fn);
28475      },
28476
28477      /**
28478       * @ngdoc method
28479       * @name $rootScope.Scope#$apply
28480       * @kind function
28481       *
28482       * @description
28483       * `$apply()` is used to execute an expression in angular from outside of the angular
28484       * framework. (For example from browser DOM events, setTimeout, XHR or third party libraries).
28485       * Because we are calling into the angular framework we need to perform proper scope life
28486       * cycle of {@link ng.$exceptionHandler exception handling},
28487       * {@link ng.$rootScope.Scope#$digest executing watches}.
28488       *
28489       * ## Life cycle
28490       *
28491       * # Pseudo-Code of `$apply()`
28492       * ```js
28493           function $apply(expr) {
28494             try {
28495               return $eval(expr);
28496             } catch (e) {
28497               $exceptionHandler(e);
28498             } finally {
28499               $root.$digest();
28500             }
28501           }
28502       * ```
28503       *
28504       *
28505       * Scope's `$apply()` method transitions through the following stages:
28506       *
28507       * 1. The {@link guide/expression expression} is executed using the
28508       *    {@link ng.$rootScope.Scope#$eval $eval()} method.
28509       * 2. Any exceptions from the execution of the expression are forwarded to the
28510       *    {@link ng.$exceptionHandler $exceptionHandler} service.
28511       * 3. The {@link ng.$rootScope.Scope#$watch watch} listeners are fired immediately after the
28512       *    expression was executed using the {@link ng.$rootScope.Scope#$digest $digest()} method.
28513       *
28514       *
28515       * @param {(string|function())=} exp An angular expression to be executed.
28516       *
28517       *    - `string`: execute using the rules as defined in {@link guide/expression expression}.
28518       *    - `function(scope)`: execute the function with current `scope` parameter.
28519       *
28520       * @returns {*} The result of evaluating the expression.
28521       */
28522      $apply: function(expr) {
28523        try {
28524          beginPhase('$apply');
28525          try {
28526            return this.$eval(expr);
28527          } finally {
28528            clearPhase();
28529          }
28530        } catch (e) {
28531          $exceptionHandler(e);
28532        } finally {
28533          try {
28534            $rootScope.$digest();
28535          } catch (e) {
28536            $exceptionHandler(e);
28537            // eslint-disable-next-line no-unsafe-finally
28538            throw e;
28539          }
28540        }
28541      },
28542
28543      /**
28544       * @ngdoc method
28545       * @name $rootScope.Scope#$applyAsync
28546       * @kind function
28547       *
28548       * @description
28549       * Schedule the invocation of $apply to occur at a later time. The actual time difference
28550       * varies across browsers, but is typically around ~10 milliseconds.
28551       *
28552       * This can be used to queue up multiple expressions which need to be evaluated in the same
28553       * digest.
28554       *
28555       * @param {(string|function())=} exp An angular expression to be executed.
28556       *
28557       *    - `string`: execute using the rules as defined in {@link guide/expression expression}.
28558       *    - `function(scope)`: execute the function with current `scope` parameter.
28559       */
28560      $applyAsync: function(expr) {
28561        var scope = this;
28562        if (expr) {
28563          applyAsyncQueue.push($applyAsyncExpression);
28564        }
28565        expr = $parse(expr);
28566        scheduleApplyAsync();
28567
28568        function $applyAsyncExpression() {
28569          scope.$eval(expr);
28570        }
28571      },
28572
28573      /**
28574       * @ngdoc method
28575       * @name $rootScope.Scope#$on
28576       * @kind function
28577       *
28578       * @description
28579       * Listens on events of a given type. See {@link ng.$rootScope.Scope#$emit $emit} for
28580       * discussion of event life cycle.
28581       *
28582       * The event listener function format is: `function(event, args...)`. The `event` object
28583       * passed into the listener has the following attributes:
28584       *
28585       *   - `targetScope` - `{Scope}`: the scope on which the event was `$emit`-ed or
28586       *     `$broadcast`-ed.
28587       *   - `currentScope` - `{Scope}`: the scope that is currently handling the event. Once the
28588       *     event propagates through the scope hierarchy, this property is set to null.
28589       *   - `name` - `{string}`: name of the event.
28590       *   - `stopPropagation` - `{function=}`: calling `stopPropagation` function will cancel
28591       *     further event propagation (available only for events that were `$emit`-ed).
28592       *   - `preventDefault` - `{function}`: calling `preventDefault` sets `defaultPrevented` flag
28593       *     to true.
28594       *   - `defaultPrevented` - `{boolean}`: true if `preventDefault` was called.
28595       *
28596       * @param {string} name Event name to listen on.
28597       * @param {function(event, ...args)} listener Function to call when the event is emitted.
28598       * @returns {function()} Returns a deregistration function for this listener.
28599       */
28600      $on: function(name, listener) {
28601        var namedListeners = this.$$listeners[name];
28602        if (!namedListeners) {
28603          this.$$listeners[name] = namedListeners = [];
28604        }
28605        namedListeners.push(listener);
28606
28607        var current = this;
28608        do {
28609          if (!current.$$listenerCount[name]) {
28610            current.$$listenerCount[name] = 0;
28611          }
28612          current.$$listenerCount[name]++;
28613        } while ((current = current.$parent));
28614
28615        var self = this;
28616        return function() {
28617          var indexOfListener = namedListeners.indexOf(listener);
28618          if (indexOfListener !== -1) {
28619            namedListeners[indexOfListener] = null;
28620            decrementListenerCount(self, 1, name);
28621          }
28622        };
28623      },
28624
28625
28626      /**
28627       * @ngdoc method
28628       * @name $rootScope.Scope#$emit
28629       * @kind function
28630       *
28631       * @description
28632       * Dispatches an event `name` upwards through the scope hierarchy notifying the
28633       * registered {@link ng.$rootScope.Scope#$on} listeners.
28634       *
28635       * The event life cycle starts at the scope on which `$emit` was called. All
28636       * {@link ng.$rootScope.Scope#$on listeners} listening for `name` event on this scope get
28637       * notified. Afterwards, the event traverses upwards toward the root scope and calls all
28638       * registered listeners along the way. The event will stop propagating if one of the listeners
28639       * cancels it.
28640       *
28641       * Any exception emitted from the {@link ng.$rootScope.Scope#$on listeners} will be passed
28642       * onto the {@link ng.$exceptionHandler $exceptionHandler} service.
28643       *
28644       * @param {string} name Event name to emit.
28645       * @param {...*} args Optional one or more arguments which will be passed onto the event listeners.
28646       * @return {Object} Event object (see {@link ng.$rootScope.Scope#$on}).
28647       */
28648      $emit: function(name, args) {
28649        var empty = [],
28650            namedListeners,
28651            scope = this,
28652            stopPropagation = false,
28653            event = {
28654              name: name,
28655              targetScope: scope,
28656              stopPropagation: function() {stopPropagation = true;},
28657              preventDefault: function() {
28658                event.defaultPrevented = true;
28659              },
28660              defaultPrevented: false
28661            },
28662            listenerArgs = concat([event], arguments, 1),
28663            i, length;
28664
28665        do {
28666          namedListeners = scope.$$listeners[name] || empty;
28667          event.currentScope = scope;
28668          for (i = 0, length = namedListeners.length; i < length; i++) {
28669
28670            // if listeners were deregistered, defragment the array
28671            if (!namedListeners[i]) {
28672              namedListeners.splice(i, 1);
28673              i--;
28674              length--;
28675              continue;
28676            }
28677            try {
28678              //allow all listeners attached to the current scope to run
28679              namedListeners[i].apply(null, listenerArgs);
28680            } catch (e) {
28681              $exceptionHandler(e);
28682            }
28683          }
28684          //if any listener on the current scope stops propagation, prevent bubbling
28685          if (stopPropagation) {
28686            event.currentScope = null;
28687            return event;
28688          }
28689          //traverse upwards
28690          scope = scope.$parent;
28691        } while (scope);
28692
28693        event.currentScope = null;
28694
28695        return event;
28696      },
28697
28698
28699      /**
28700       * @ngdoc method
28701       * @name $rootScope.Scope#$broadcast
28702       * @kind function
28703       *
28704       * @description
28705       * Dispatches an event `name` downwards to all child scopes (and their children) notifying the
28706       * registered {@link ng.$rootScope.Scope#$on} listeners.
28707       *
28708       * The event life cycle starts at the scope on which `$broadcast` was called. All
28709       * {@link ng.$rootScope.Scope#$on listeners} listening for `name` event on this scope get
28710       * notified. Afterwards, the event propagates to all direct and indirect scopes of the current
28711       * scope and calls all registered listeners along the way. The event cannot be canceled.
28712       *
28713       * Any exception emitted from the {@link ng.$rootScope.Scope#$on listeners} will be passed
28714       * onto the {@link ng.$exceptionHandler $exceptionHandler} service.
28715       *
28716       * @param {string} name Event name to broadcast.
28717       * @param {...*} args Optional one or more arguments which will be passed onto the event listeners.
28718       * @return {Object} Event object, see {@link ng.$rootScope.Scope#$on}
28719       */
28720      $broadcast: function(name, args) {
28721        var target = this,
28722            current = target,
28723            next = target,
28724            event = {
28725              name: name,
28726              targetScope: target,
28727              preventDefault: function() {
28728                event.defaultPrevented = true;
28729              },
28730              defaultPrevented: false
28731            };
28732
28733        if (!target.$$listenerCount[name]) return event;
28734
28735        var listenerArgs = concat([event], arguments, 1),
28736            listeners, i, length;
28737
28738        //down while you can, then up and next sibling or up and next sibling until back at root
28739        while ((current = next)) {
28740          event.currentScope = current;
28741          listeners = current.$$listeners[name] || [];
28742          for (i = 0, length = listeners.length; i < length; i++) {
28743            // if listeners were deregistered, defragment the array
28744            if (!listeners[i]) {
28745              listeners.splice(i, 1);
28746              i--;
28747              length--;
28748              continue;
28749            }
28750
28751            try {
28752              listeners[i].apply(null, listenerArgs);
28753            } catch (e) {
28754              $exceptionHandler(e);
28755            }
28756          }
28757
28758          // Insanity Warning: scope depth-first traversal
28759          // yes, this code is a bit crazy, but it works and we have tests to prove it!
28760          // this piece should be kept in sync with the traversal in $digest
28761          // (though it differs due to having the extra check for $$listenerCount)
28762          if (!(next = ((current.$$listenerCount[name] && current.$$childHead) ||
28763              (current !== target && current.$$nextSibling)))) {
28764            while (current !== target && !(next = current.$$nextSibling)) {
28765              current = current.$parent;
28766            }
28767          }
28768        }
28769
28770        event.currentScope = null;
28771        return event;
28772      }
28773    };
28774
28775    var $rootScope = new Scope();
28776
28777    //The internal queues. Expose them on the $rootScope for debugging/testing purposes.
28778    var asyncQueue = $rootScope.$$asyncQueue = [];
28779    var postDigestQueue = $rootScope.$$postDigestQueue = [];
28780    var applyAsyncQueue = $rootScope.$$applyAsyncQueue = [];
28781
28782    var postDigestQueuePosition = 0;
28783
28784    return $rootScope;
28785
28786
28787    function beginPhase(phase) {
28788      if ($rootScope.$$phase) {
28789        throw $rootScopeMinErr('inprog', '{0} already in progress', $rootScope.$$phase);
28790      }
28791
28792      $rootScope.$$phase = phase;
28793    }
28794
28795    function clearPhase() {
28796      $rootScope.$$phase = null;
28797    }
28798
28799    function incrementWatchersCount(current, count) {
28800      do {
28801        current.$$watchersCount += count;
28802      } while ((current = current.$parent));
28803    }
28804
28805    function decrementListenerCount(current, count, name) {
28806      do {
28807        current.$$listenerCount[name] -= count;
28808
28809        if (current.$$listenerCount[name] === 0) {
28810          delete current.$$listenerCount[name];
28811        }
28812      } while ((current = current.$parent));
28813    }
28814
28815    /**
28816     * function used as an initial value for watchers.
28817     * because it's unique we can easily tell it apart from other values
28818     */
28819    function initWatchVal() {}
28820
28821    function flushApplyAsync() {
vendor: 4,475 bytes, lines 28822-28938
28822      while (applyAsyncQueue.length) {
28823        try {
28824          applyAsyncQueue.shift()();
28825        } catch (e) {
28826          $exceptionHandler(e);
28827        }
28828      }
28829      applyAsyncId = null;
28830    }
28831
28832    function scheduleApplyAsync() {
28833      if (applyAsyncId === null) {
28834        applyAsyncId = $browser.defer(function() {
28835          $rootScope.$apply(flushApplyAsync);
28836        });
28837      }
28838    }
28839  }];
28840}
28841
28842/**
28843 * @ngdoc service
28844 * @name $rootElement
28845 *
28846 * @description
28847 * The root element of Angular application. This is either the element where {@link
28848 * ng.directive:ngApp ngApp} was declared or the element passed into
28849 * {@link angular.bootstrap}. The element represents the root element of application. It is also the
28850 * location where the application's {@link auto.$injector $injector} service gets
28851 * published, and can be retrieved using `$rootElement.injector()`.
28852 */
28853
28854
28855// the implementation is in angular.bootstrap
28856
28857/**
28858 * @this
28859 * @description
28860 * Private service to sanitize uris for links and images. Used by $compile and $sanitize.
28861 */
28862function $$SanitizeUriProvider() {
28863  var aHrefSanitizationWhitelist = /^\s*(https?|ftp|mailto|tel|file):/,
28864    imgSrcSanitizationWhitelist = /^\s*((https?|ftp|file|blob):|data:image\/)/;
28865
28866  /**
28867   * @description
28868   * Retrieves or overrides the default regular expression that is used for whitelisting of safe
28869   * urls during a[href] sanitization.
28870   *
28871   * The sanitization is a security measure aimed at prevent XSS attacks via html links.
28872   *
28873   * Any url about to be assigned to a[href] via data-binding is first normalized and turned into
28874   * an absolute url. Afterwards, the url is matched against the `aHrefSanitizationWhitelist`
28875   * regular expression. If a match is found, the original url is written into the dom. Otherwise,
28876   * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM.
28877   *
28878   * @param {RegExp=} regexp New regexp to whitelist urls with.
28879   * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
28880   *    chaining otherwise.
28881   */
28882  this.aHrefSanitizationWhitelist = function(regexp) {
28883    if (isDefined(regexp)) {
28884      aHrefSanitizationWhitelist = regexp;
28885      return this;
28886    }
28887    return aHrefSanitizationWhitelist;
28888  };
28889
28890
28891  /**
28892   * @description
28893   * Retrieves or overrides the default regular expression that is used for whitelisting of safe
28894   * urls during img[src] sanitization.
28895   *
28896   * The sanitization is a security measure aimed at prevent XSS attacks via html links.
28897   *
28898   * Any url about to be assigned to img[src] via data-binding is first normalized and turned into
28899   * an absolute url. Afterwards, the url is matched against the `imgSrcSanitizationWhitelist`
28900   * regular expression. If a match is found, the original url is written into the dom. Otherwise,
28901   * the absolute url is prefixed with `'unsafe:'` string and only then is it written into the DOM.
28902   *
28903   * @param {RegExp=} regexp New regexp to whitelist urls with.
28904   * @returns {RegExp|ng.$compileProvider} Current RegExp if called without value or self for
28905   *    chaining otherwise.
28906   */
28907  this.imgSrcSanitizationWhitelist = function(regexp) {
28908    if (isDefined(regexp)) {
28909      imgSrcSanitizationWhitelist = regexp;
28910      return this;
28911    }
28912    return imgSrcSanitizationWhitelist;
28913  };
28914
28915  this.$get = function() {
28916    return function sanitizeUri(uri, isImage) {
28917      var regex = isImage ? imgSrcSanitizationWhitelist : aHrefSanitizationWhitelist;
28918      var normalizedVal;
28919      normalizedVal = urlResolve(uri).href;
28920      if (normalizedVal !== '' && !normalizedVal.match(regex)) {
28921        return 'unsafe:' + normalizedVal;
28922      }
28923      return uri;
28924    };
28925  };
28926}
28927
28928/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
28929 *     Any commits to this file should be reviewed with security in mind.  *
28930 *   Changes to this file can potentially create security vulnerabilities. *
28931 *          An approval from 2 Core members with history of modifying      *
28932 *                         this file is required.                          *
28933 *                                                                         *
28934 *  Does the change somehow allow for arbitrary javascript to be executed? *
28935 *    Or allows for someone to change the prototype of built-in objects?   *
28936 *     Or gives undesired access to variables likes document or window?    *
28937 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
28938
28939/* exported $SceProvider, $SceDelegateProvider */
28940
28941var $sceMinErr = minErr('$sce');
28942
28943var SCE_CONTEXTS = {
28944  HTML: 'html',
28945  CSS: 'css',
28946  URL: 'url',
28947  // RESOURCE_URL is a subtype of URL used in contexts where a privileged resource is sourced from a
28948  // url.  (e.g. ng-include, script src, templateUrl)
28949  RESOURCE_URL: 'resourceUrl',
28950  JS: 'js'
28951};
28952
28953// Helper functions follow.
28954
28955var UNDERSCORE_LOWERCASE_REGEXP = /_([a-z])/g;
28956
28957function snakeToCamel(name) {
28958  return name
28959    .replace(UNDERSCORE_LOWERCASE_REGEXP, fnCamelCaseReplace);
28960}
28961
28962function adjustMatcher(matcher) {
28963  if (matcher === 'self') {
28964    return matcher;
28965  } else if (isString(matcher)) {
28966    // Strings match exactly except for 2 wildcards - '*' and '**'.
28967    // '*' matches any character except those from the set ':/.?&'.
28968    // '**' matches any character (like .* in a RegExp).
28969    // More than 2 *'s raises an error as it's ill defined.
28970    if (matcher.indexOf('***') > -1) {
28971      throw $sceMinErr('iwcard',
28972          'Illegal sequence *** in string matcher.  String: {0}', matcher);
28973    }
28974    matcher = escapeForRegexp(matcher).
28975                  replace(/\\\*\\\*/g, '.*').
28976                  replace(/\\\*/g, '[^:/.?&;]*');
28977    return new RegExp('^' + matcher + '$');
28978  } else if (isRegExp(matcher)) {
28979    // The only other type of matcher allowed is a Regexp.
28980    // Match entire URL / disallow partial matches.
28981    // Flags are reset (i.e. no global, ignoreCase or multiline)
28982    return new RegExp('^' + matcher.source + '$');
28983  } else {
28984    throw $sceMinErr('imatcher',
28985        'Matchers may only be "self", string patterns or RegExp objects');
28986  }
28987}
28988
28989
28990function adjustMatchers(matchers) {
28991  var adjustedMatchers = [];
28992  if (isDefined(matchers)) {
28993    forEach(matchers, function(matcher) {
28994      adjustedMatchers.push(adjustMatcher(matcher));
28995    });
28996  }
28997  return adjustedMatchers;
28998}
28999
29000
29001/**
29002 * @ngdoc service
29003 * @name $sceDelegate
29004 * @kind function
29005 *
29006 * @description
29007 *
29008 * `$sceDelegate` is a service that is used by the `$sce` service to provide {@link ng.$sce Strict
29009 * Contextual Escaping (SCE)} services to AngularJS.
29010 *
29011 * Typically, you would configure or override the {@link ng.$sceDelegate $sceDelegate} instead of
29012 * the `$sce` service to customize the way Strict Contextual Escaping works in AngularJS.  This is
29013 * because, while the `$sce` provides numerous shorthand methods, etc., you really only need to
29014 * override 3 core functions (`trustAs`, `getTrusted` and `valueOf`) to replace the way things
29015 * work because `$sce` delegates to `$sceDelegate` for these operations.
29016 *
29017 * Refer {@link ng.$sceDelegateProvider $sceDelegateProvider} to configure this service.
29018 *
29019 * The default instance of `$sceDelegate` should work out of the box with little pain.  While you
29020 * can override it completely to change the behavior of `$sce`, the common case would
29021 * involve configuring the {@link ng.$sceDelegateProvider $sceDelegateProvider} instead by setting
29022 * your own whitelists and blacklists for trusting URLs used for loading AngularJS resources such as
29023 * templates.  Refer {@link ng.$sceDelegateProvider#resourceUrlWhitelist
29024 * $sceDelegateProvider.resourceUrlWhitelist} and {@link
29025 * ng.$sceDelegateProvider#resourceUrlBlacklist $sceDelegateProvider.resourceUrlBlacklist}
29026 */
29027
29028/**
29029 * @ngdoc provider
29030 * @name $sceDelegateProvider
29031 * @this
29032 *
29033 * @description
29034 *
29035 * The `$sceDelegateProvider` provider allows developers to configure the {@link ng.$sceDelegate
29036 * $sceDelegate} service.  This allows one to get/set the whitelists and blacklists used to ensure
29037 * that the URLs used for sourcing Angular templates are safe.  Refer {@link
29038 * ng.$sceDelegateProvider#resourceUrlWhitelist $sceDelegateProvider.resourceUrlWhitelist} and
29039 * {@link ng.$sceDelegateProvider#resourceUrlBlacklist $sceDelegateProvider.resourceUrlBlacklist}
29040 *
29041 * For the general details about this service in Angular, read the main page for {@link ng.$sce
29042 * Strict Contextual Escaping (SCE)}.
29043 *
29044 * **Example**:  Consider the following case. <a name="example"></a>
29045 *
29046 * - your app is hosted at url `http://myapp.example.com/`
29047 * - but some of your templates are hosted on other domains you control such as
29048 *   `http://srv01.assets.example.com/`, `http://srv02.assets.example.com/`, etc.
29049 * - and you have an open redirect at `http://myapp.example.com/clickThru?...`.
29050 *
29051 * Here is what a secure configuration for this scenario might look like:
29052 *
29053 * ```
29054 *  angular.module('myApp', []).config(function($sceDelegateProvider) {
29055 *    $sceDelegateProvider.resourceUrlWhitelist([
29056 *      // Allow same origin resource loads.
29057 *      'self',
29058 *      // Allow loading from our assets domain.  Notice the difference between * and **.
29059 *      'http://srv*.assets.example.com/**'
29060 *    ]);
29061 *
29062 *    // The blacklist overrides the whitelist so the open redirect here is blocked.
29063 *    $sceDelegateProvider.resourceUrlBlacklist([
29064 *      'http://myapp.example.com/clickThru**'
29065 *    ]);
29066 *  });
29067 * ```
29068 */
29069
29070function $SceDelegateProvider() {
29071  this.SCE_CONTEXTS = SCE_CONTEXTS;
29072
29073  // Resource URLs can also be trusted by policy.
29074  var resourceUrlWhitelist = ['self'],
29075      resourceUrlBlacklist = [];
29076
29077  /**
29078   * @ngdoc method
29079   * @name $sceDelegateProvider#resourceUrlWhitelist
29080   * @kind function
29081   *
29082   * @param {Array=} whitelist When provided, replaces the resourceUrlWhitelist with the value
29083   *    provided.  This must be an array or null.  A snapshot of this array is used so further
29084   *    changes to the array are ignored.
29085   *
29086   *    Follow {@link ng.$sce#resourceUrlPatternItem this link} for a description of the items
29087   *    allowed in this array.
vendor: 4,196 bytes, lines 29088-29214
29088   *
29089   *    <div class="alert alert-warning">
29090   *    **Note:** an empty whitelist array will block all URLs!
29091   *    </div>
29092   *
29093   * @return {Array} the currently set whitelist array.
29094   *
29095   * The **default value** when no whitelist has been explicitly set is `['self']` allowing only
29096   * same origin resource requests.
29097   *
29098   * @description
29099   * Sets/Gets the whitelist of trusted resource URLs.
29100   */
29101  this.resourceUrlWhitelist = function(value) {
29102    if (arguments.length) {
29103      resourceUrlWhitelist = adjustMatchers(value);
29104    }
29105    return resourceUrlWhitelist;
29106  };
29107
29108  /**
29109   * @ngdoc method
29110   * @name $sceDelegateProvider#resourceUrlBlacklist
29111   * @kind function
29112   *
29113   * @param {Array=} blacklist When provided, replaces the resourceUrlBlacklist with the value
29114   *    provided.  This must be an array or null.  A snapshot of this array is used so further
29115   *    changes to the array are ignored.
29116   *
29117   *    Follow {@link ng.$sce#resourceUrlPatternItem this link} for a description of the items
29118   *    allowed in this array.
29119   *
29120   *    The typical usage for the blacklist is to **block
29121   *    [open redirects](http://cwe.mitre.org/data/definitions/601.html)** served by your domain as
29122   *    these would otherwise be trusted but actually return content from the redirected domain.
29123   *
29124   *    Finally, **the blacklist overrides the whitelist** and has the final say.
29125   *
29126   * @return {Array} the currently set blacklist array.
29127   *
29128   * The **default value** when no whitelist has been explicitly set is the empty array (i.e. there
29129   * is no blacklist.)
29130   *
29131   * @description
29132   * Sets/Gets the blacklist of trusted resource URLs.
29133   */
29134
29135  this.resourceUrlBlacklist = function(value) {
29136    if (arguments.length) {
29137      resourceUrlBlacklist = adjustMatchers(value);
29138    }
29139    return resourceUrlBlacklist;
29140  };
29141
29142  this.$get = ['$injector', function($injector) {
29143
29144    var htmlSanitizer = function htmlSanitizer(html) {
29145      throw $sceMinErr('unsafe', 'Attempting to use an unsafe value in a safe context.');
29146    };
29147
29148    if ($injector.has('$sanitize')) {
29149      htmlSanitizer = $injector.get('$sanitize');
29150    }
29151
29152
29153    function matchUrl(matcher, parsedUrl) {
29154      if (matcher === 'self') {
29155        return urlIsSameOrigin(parsedUrl);
29156      } else {
29157        // definitely a regex.  See adjustMatchers()
29158        return !!matcher.exec(parsedUrl.href);
29159      }
29160    }
29161
29162    function isResourceUrlAllowedByPolicy(url) {
29163      var parsedUrl = urlResolve(url.toString());
29164      var i, n, allowed = false;
29165      // Ensure that at least one item from the whitelist allows this url.
29166      for (i = 0, n = resourceUrlWhitelist.length; i < n; i++) {
29167        if (matchUrl(resourceUrlWhitelist[i], parsedUrl)) {
29168          allowed = true;
29169          break;
29170        }
29171      }
29172      if (allowed) {
29173        // Ensure that no item from the blacklist blocked this url.
29174        for (i = 0, n = resourceUrlBlacklist.length; i < n; i++) {
29175          if (matchUrl(resourceUrlBlacklist[i], parsedUrl)) {
29176            allowed = false;
29177            break;
29178          }
29179        }
29180      }
29181      return allowed;
29182    }
29183
29184    function generateHolderType(Base) {
29185      var holderType = function TrustedValueHolderType(trustedValue) {
29186        this.$$unwrapTrustedValue = function() {
29187          return trustedValue;
29188        };
29189      };
29190      if (Base) {
29191        holderType.prototype = new Base();
29192      }
29193      holderType.prototype.valueOf = function sceValueOf() {
29194        return this.$$unwrapTrustedValue();
29195      };
29196      holderType.prototype.toString = function sceToString() {
29197        return this.$$unwrapTrustedValue().toString();
29198      };
29199      return holderType;
29200    }
29201
29202    var trustedValueHolderBase = generateHolderType(),
29203        byType = {};
29204
29205    byType[SCE_CONTEXTS.HTML] = generateHolderType(trustedValueHolderBase);
29206    byType[SCE_CONTEXTS.CSS] = generateHolderType(trustedValueHolderBase);
29207    byType[SCE_CONTEXTS.URL] = generateHolderType(trustedValueHolderBase);
29208    byType[SCE_CONTEXTS.JS] = generateHolderType(trustedValueHolderBase);
29209    byType[SCE_CONTEXTS.RESOURCE_URL] = generateHolderType(byType[SCE_CONTEXTS.URL]);
29210
29211    /**
29212     * @ngdoc method
29213     * @name $sceDelegate#trustAs
29214     *
29215     * @description
29216     * Returns an object that is trusted by angular for use in specified strict
29217     * contextual escaping contexts (such as ng-bind-html, ng-include, any src
29218     * attribute interpolation, any dom event binding attribute interpolation
29219     * such as for onclick,  etc.) that uses the provided value.
29220     * See {@link ng.$sce $sce} for enabling strict contextual escaping.
29221     *
29222     * @param {string} type The kind of context in which this value is safe for use.  e.g. url,
29223     *   resourceUrl, html, js and css.
29224     * @param {*} value The value that that should be considered trusted/safe.
29225     * @returns {*} A value that can be used to stand in for the provided `value` in places
29226     * where Angular expects a $sce.trustAs() return value.
29227     */
29228    function trustAs(type, trustedValue) {
29229      var Constructor = (byType.hasOwnProperty(type) ? byType[type] : null);
29230      if (!Constructor) {
29231        throw $sceMinErr('icontext',
29232            'Attempted to trust a value in invalid context. Context: {0}; Value: {1}',
29233            type, trustedValue);
29234      }
29235      if (trustedValue === null || isUndefined(trustedValue) || trustedValue === '') {
29236        return trustedValue;
29237      }
29238      // All the current contexts in SCE_CONTEXTS happen to be strings.  In order to avoid trusting
29239      // mutable objects, we ensure here that the value passed in is actually a string.
29240      if (typeof trustedValue !== 'string') {
29241        throw $sceMinErr('itype',
29242            'Attempted to trust a non-string value in a content requiring a string: Context: {0}',
29243            type);
29244      }
29245      return new Constructor(trustedValue);
29246    }
29247
29248    /**
29249     * @ngdoc method
29250     * @name $sceDelegate#valueOf
29251     *
29252     * @description
29253     * If the passed parameter had been returned by a prior call to {@link ng.$sceDelegate#trustAs
29254     * `$sceDelegate.trustAs`}, returns the value that had been passed to {@link
29255     * ng.$sceDelegate#trustAs `$sceDelegate.trustAs`}.
29256     *
29257     * If the passed parameter is not a value that had been returned by {@link
29258     * ng.$sceDelegate#trustAs `$sceDelegate.trustAs`}, returns it as-is.
29259     *
29260     * @param {*} value The result of a prior {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs`}
29261     *      call or anything else.
29262     * @returns {*} The `value` that was originally provided to {@link ng.$sceDelegate#trustAs
29263     *     `$sceDelegate.trustAs`} if `value` is the result of such a call.  Otherwise, returns
29264     *     `value` unchanged.
29265     */
29266    function valueOf(maybeTrusted) {
29267      if (maybeTrusted instanceof trustedValueHolderBase) {
29268        return maybeTrusted.$$unwrapTrustedValue();
29269      } else {
29270        return maybeTrusted;
29271      }
29272    }
29273
29274    /**
29275     * @ngdoc method
29276     * @name $sceDelegate#getTrusted
29277     *
29278     * @description
29279     * Takes the result of a {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs`} call and
29280     * returns the originally supplied value if the queried context type is a supertype of the
29281     * created type.  If this condition isn't satisfied, throws an exception.
29282     *
29283     * <div class="alert alert-danger">
29284     * Disabling auto-escaping is extremely dangerous, it usually creates a Cross Site Scripting
29285     * (XSS) vulnerability in your application.
29286     * </div>
29287     *
29288     * @param {string} type The kind of context in which this value is to be used.
29289     * @param {*} maybeTrusted The result of a prior {@link ng.$sceDelegate#trustAs
29290     *     `$sceDelegate.trustAs`} call.
29291     * @returns {*} The value the was originally provided to {@link ng.$sceDelegate#trustAs
29292     *     `$sceDelegate.trustAs`} if valid in this context.  Otherwise, throws an exception.
29293     */
29294    function getTrusted(type, maybeTrusted) {
29295      if (maybeTrusted === null || isUndefined(maybeTrusted) || maybeTrusted === '') {
29296        return maybeTrusted;
29297      }
29298      var constructor = (byType.hasOwnProperty(type) ? byType[type] : null);
29299      if (constructor && maybeTrusted instanceof constructor) {
29300        return maybeTrusted.$$unwrapTrustedValue();
29301      }
29302      // If we get here, then we may only take one of two actions.
29303      // 1. sanitize the value for the requested type, or
29304      // 2. throw an exception.
29305      if (type === SCE_CONTEXTS.RESOURCE_URL) {
29306        if (isResourceUrlAllowedByPolicy(maybeTrusted)) {
29307          return maybeTrusted;
29308        } else {
29309          throw $sceMinErr('insecurl',
29310              'Blocked loading resource from url not allowed by $sceDelegate policy.  URL: {0}',
29311              maybeTrusted.toString());
29312        }
29313      } else if (type === SCE_CONTEXTS.HTML) {
29314        return htmlSanitizer(maybeTrusted);
29315      }
29316      throw $sceMinErr('unsafe', 'Attempting to use an unsafe value in a safe context.');
29317    }
29318
29319    return { trustAs: trustAs,
29320             getTrusted: getTrusted,
29321             valueOf: valueOf };
29322  }];
29323}
29324
29325
29326/**
29327 * @ngdoc provider
29328 * @name $sceProvider
29329 * @this
29330 *
29331 * @description
29332 *
29333 * The $sceProvider provider allows developers to configure the {@link ng.$sce $sce} service.
29334 * -   enable/disable Strict Contextual Escaping (SCE) in a module
29335 * -   override the default implementation with a custom delegate
29336 *
29337 * Read more about {@link ng.$sce Strict Contextual Escaping (SCE)}.
29338 */
29339
29340/**
29341 * @ngdoc service
29342 * @name $sce
29343 * @kind function
29344 *
29345 * @description
29346 *
29347 * `$sce` is a service that provides Strict Contextual Escaping services to AngularJS.
29348 *
29349 * # Strict Contextual Escaping
29350 *
29351 * Strict Contextual Escaping (SCE) is a mode in which AngularJS requires bindings in certain
29352 * contexts to result in a value that is marked as safe to use for that context.  One example of
29353 * such a context is binding arbitrary html controlled by the user via `ng-bind-html`.  We refer
29354 * to these contexts as privileged or SCE contexts.
29355 *
29356 * As of version 1.2, Angular ships with SCE enabled by default.
29357 *
29358 * Note:  When enabled (the default), IE<11 in quirks mode is not supported.  In this mode, IE<11 allow
29359 * one to execute arbitrary javascript by the use of the expression() syntax.  Refer
29360 * <http://blogs.msdn.com/b/ie/archive/2008/10/16/ending-expressions.aspx> to learn more about them.
29361 * You can ensure your document is in standards mode and not quirks mode by adding `<!doctype html>`
29362 * to the top of your HTML document.
29363 *
29364 * SCE assists in writing code in a way that (a) is secure by default and (b) makes auditing for
29365 * security vulnerabilities such as XSS, clickjacking, etc. a lot easier.
29366 *
29367 * Here's an example of a binding in a privileged context:
29368 *
29369 * ```
29370 * <input ng-model="userHtml" aria-label="User input">
29371 * <div ng-bind-html="userHtml"></div>
29372 * ```
29373 *
29374 * Notice that `ng-bind-html` is bound to `userHtml` controlled by the user.  With SCE
29375 * disabled, this application allows the user to render arbitrary HTML into the DIV.
29376 * In a more realistic example, one may be rendering user comments, blog articles, etc. via
29377 * bindings.  (HTML is just one example of a context where rendering user controlled input creates
29378 * security vulnerabilities.)
29379 *
29380 * For the case of HTML, you might use a library, either on the client side, or on the server side,
29381 * to sanitize unsafe HTML before binding to the value and rendering it in the document.
29382 *
29383 * How would you ensure that every place that used these types of bindings was bound to a value that
29384 * was sanitized by your library (or returned as safe for rendering by your server?)  How can you
29385 * ensure that you didn't accidentally delete the line that sanitized the value, or renamed some
29386 * properties/fields and forgot to update the binding to the sanitized value?
29387 *
29388 * To be secure by default, you want to ensure that any such bindings are disallowed unless you can
29389 * determine that something explicitly says it's safe to use a value for binding in that
29390 * context.  You can then audit your code (a simple grep would do) to ensure that this is only done
29391 * for those values that you can easily tell are safe - because they were received from your server,
29392 * sanitized by your library, etc.  You can organize your codebase to help with this - perhaps
29393 * allowing only the files in a specific directory to do this.  Ensuring that the internal API
29394 * exposed by that code doesn't markup arbitrary values as safe then becomes a more manageable task.
29395 *
29396 * In the case of AngularJS' SCE service, one uses {@link ng.$sce#trustAs $sce.trustAs}
29397 * (and shorthand methods such as {@link ng.$sce#trustAsHtml $sce.trustAsHtml}, etc.) to
29398 * obtain values that will be accepted by SCE / privileged contexts.
29399 *
29400 *
29401 * ## How does it work?
29402 *
29403 * In privileged contexts, directives and code will bind to the result of {@link ng.$sce#getTrusted
29404 * $sce.getTrusted(context, value)} rather than to the value directly.  Directives use {@link
29405 * ng.$sce#parseAs $sce.parseAs} rather than `$parse` to watch attribute bindings, which performs the
29406 * {@link ng.$sce#getTrusted $sce.getTrusted} behind the scenes on non-constant literals.
29407 *
29408 * As an example, {@link ng.directive:ngBindHtml ngBindHtml} uses {@link
29409 * ng.$sce#parseAsHtml $sce.parseAsHtml(binding expression)}.  Here's the actual code (slightly
29410 * simplified):
29411 *
29412 * ```
29413 * var ngBindHtmlDirective = ['$sce', function($sce) {
29414 *   return function(scope, element, attr) {
29415 *     scope.$watch($sce.parseAsHtml(attr.ngBindHtml), function(value) {
29416 *       element.html(value || '');
29417 *     });
29418 *   };
29419 * }];
29420 * ```
29421 *
29422 * ## Impact on loading templates
29423 *
29424 * This applies both to the {@link ng.directive:ngInclude `ng-include`} directive as well as
29425 * `templateUrl`'s specified by {@link guide/directive directives}.
29426 *
29427 * By default, Angular only loads templates from the same domain and protocol as the application
29428 * document.  This is done by calling {@link ng.$sce#getTrustedResourceUrl
29429 * $sce.getTrustedResourceUrl} on the template URL.  To load templates from other domains and/or
29430 * protocols, you may either {@link ng.$sceDelegateProvider#resourceUrlWhitelist whitelist
29431 * them} or {@link ng.$sce#trustAsResourceUrl wrap it} into a trusted value.
29432 *
29433 * *Please note*:
29434 * The browser's
29435 * [Same Origin Policy](https://code.google.com/p/browsersec/wiki/Part2#Same-origin_policy_for_XMLHttpRequest)
29436 * and [Cross-Origin Resource Sharing (CORS)](http://www.w3.org/TR/cors/)
29437 * policy apply in addition to this and may further restrict whether the template is successfully
29438 * loaded.  This means that without the right CORS policy, loading templates from a different domain
29439 * won't work on all browsers.  Also, loading templates from `file://` URL does not work on some
29440 * browsers.
29441 *
29442 * ## This feels like too much overhead
29443 *
29444 * It's important to remember that SCE only applies to interpolation expressions.
29445 *
29446 * If your expressions are constant literals, they're automatically trusted and you don't need to
29447 * call `$sce.trustAs` on them (remember to include the `ngSanitize` module) (e.g.
29448 * `<div ng-bind-html="'<b>implicitly trusted</b>'"></div>`) just works.
29449 *
29450 * Additionally, `a[href]` and `img[src]` automatically sanitize their URLs and do not pass them
29451 * through {@link ng.$sce#getTrusted $sce.getTrusted}.  SCE doesn't play a role here.
29452 *
29453 * The included {@link ng.$sceDelegate $sceDelegate} comes with sane defaults to allow you to load
29454 * templates in `ng-include` from your application's domain without having to even know about SCE.
29455 * It blocks loading templates from other domains or loading templates over http from an https
29456 * served document.  You can change these by setting your own custom {@link
29457 * ng.$sceDelegateProvider#resourceUrlWhitelist whitelists} and {@link
29458 * ng.$sceDelegateProvider#resourceUrlBlacklist blacklists} for matching such URLs.
29459 *
29460 * This significantly reduces the overhead.  It is far easier to pay the small overhead and have an
29461 * application that's secure and can be audited to verify that with much more ease than bolting
29462 * security onto an application later.
29463 *
29464 * <a name="contexts"></a>
29465 * ## What trusted context types are supported?
29466 *
29467 * | Context             | Notes          |
29468 * |---------------------|----------------|
29469 * | `$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. |
29470 * | `$sce.CSS`          | For CSS that's safe to source into the application.  Currently unused.  Feel free to use it in your own directives. |
29471 * | `$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. |
29472 * | `$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`, `VIDEO`, `AUDIO`, `SOURCE`, and `TRACK` (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. |
29473 * | `$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. |
29474 *
29475 * ## Format of items in {@link ng.$sceDelegateProvider#resourceUrlWhitelist resourceUrlWhitelist}/{@link ng.$sceDelegateProvider#resourceUrlBlacklist Blacklist} <a name="resourceUrlPatternItem"></a>
29476 *
29477 *  Each element in these arrays must be one of the following:
29478 *
29479 *  - **'self'**
29480 *    - The special **string**, `'self'`, can be used to match against all URLs of the **same
29481 *      domain** as the application document using the **same protocol**.
29482 *  - **String** (except the special value `'self'`)
29483 *    - The string is matched against the full *normalized / absolute URL* of the resource
29484 *      being tested (substring matches are not good enough.)
29485 *    - There are exactly **two wildcard sequences** - `*` and `**`.  All other characters
29486 *      match themselves.
29487 *    - `*`: matches zero or more occurrences of any character other than one of the following 6
29488 *      characters: '`:`', '`/`', '`.`', '`?`', '`&`' and '`;`'.  It's a useful wildcard for use
29489 *      in a whitelist.
29490 *    - `**`: matches zero or more occurrences of *any* character.  As such, it's not
29491 *      appropriate for use in a scheme, domain, etc. as it would match too much.  (e.g.
29492 *      http://**.example.com/ would match http://evil.com/?ignore=.example.com/ and that might
29493 *      not have been the intention.)  Its usage at the very end of the path is ok.  (e.g.
29494 *      http://foo.example.com/templates/**).
29495 *  - **RegExp** (*see caveat below*)
29496 *    - *Caveat*:  While regular expressions are powerful and offer great flexibility,  their syntax
29497 *      (and all the inevitable escaping) makes them *harder to maintain*.  It's easy to
29498 *      accidentally introduce a bug when one updates a complex expression (imho, all regexes should
29499 *      have good test coverage).  For instance, the use of `.` in the regex is correct only in a
29500 *      small number of cases.  A `.` character in the regex used when matching the scheme or a
29501 *      subdomain could be matched against a `:` or literal `.` that was likely not intended.   It
29502 *      is highly recommended to use the string patterns and only fall back to regular expressions
29503 *      as a last resort.
29504 *    - The regular expression must be an instance of RegExp (i.e. not a string.)  It is
29505 *      matched against the **entire** *normalized / absolute URL* of the resource being tested
29506 *      (even when the RegExp did not have the `^` and `$` codes.)  In addition, any flags
29507 *      present on the RegExp (such as multiline, global, ignoreCase) are ignored.
29508 *    - If you are generating your JavaScript from some other templating engine (not
29509 *      recommended, e.g. in issue [#4006](https://github.com/angular/angular.js/issues/4006)),
29510 *      remember to escape your regular expression (and be aware that you might need more than
29511 *      one level of escaping depending on your templating engine and the way you interpolated
29512 *      the value.)  Do make use of your platform's escaping mechanism as it might be good
29513 *      enough before coding your own.  E.g. Ruby has
29514 *      [Regexp.escape(str)](http://www.ruby-doc.org/core-2.0.0/Regexp.html#method-c-escape)
29515 *      and Python has [re.escape](http://docs.python.org/library/re.html#re.escape).
29516 *      Javascript lacks a similar built in function for escaping.  Take a look at Google
29517 *      Closure library's [goog.string.regExpEscape(s)](
29518 *      http://docs.closure-library.googlecode.com/git/closure_goog_string_string.js.source.html#line962).
29519 *
29520 * Refer {@link ng.$sceDelegateProvider $sceDelegateProvider} for an example.
29521 *
29522 * ## Show me an example using SCE.
29523 *
29524 * <example module="mySceApp" deps="angular-sanitize.js" name="sce-service">
29525 * <file name="index.html">
29526 *   <div ng-controller="AppController as myCtrl">
29527 *     <i ng-bind-html="myCtrl.explicitlyTrustedHtml" id="explicitlyTrustedHtml"></i><br><br>
29528 *     <b>User comments</b><br>
29529 *     By default, HTML that isn't explicitly trusted (e.g. Alice's comment) is sanitized when
29530 *     $sanitize is available.  If $sanitize isn't available, this results in an error instead of an
29531 *     exploit.
29532 *     <div class="well">
29533 *       <div ng-repeat="userComment in myCtrl.userComments">
29534 *         <b>{{userComment.name}}</b>:
29535 *         <span ng-bind-html="userComment.htmlComment" class="htmlComment"></span>
29536 *         <br>
29537 *       </div>
29538 *     </div>
29539 *   </div>
29540 * </file>
29541 *
29542 * <file name="script.js">
29543 *   angular.module('mySceApp', ['ngSanitize'])
29544 *     .controller('AppController', ['$http', '$templateCache', '$sce',
29545 *       function AppController($http, $templateCache, $sce) {
29546 *         var self = this;
29547 *         $http.get('test_data.json', {cache: $templateCache}).then(function(response) {
29548 *           self.userComments = response.data;
29549 *         });
29550 *         self.explicitlyTrustedHtml = $sce.trustAsHtml(
29551 *             '<span onmouseover="this.textContent=&quot;Explicitly trusted HTML bypasses ' +
29552 *             'sanitization.&quot;">Hover over this text.</span>');
29553 *       }]);
29554 * </file>
29555 *
29556 * <file name="test_data.json">
29557 * [
29558 *   { "name": "Alice",
29559 *     "htmlComment":
29560 *         "<span onmouseover='this.textContent=\"PWN3D!\"'>Is <i>anyone</i> reading this?</span>"
29561 *   },
29562 *   { "name": "Bob",
29563 *     "htmlComment": "<i>Yes!</i>  Am I the only other one?"
29564 *   }
29565 * ]
29566 * </file>
29567 *
29568 * <file name="protractor.js" type="protractor">
29569 *   describe('SCE doc demo', function() {
29570 *     it('should sanitize untrusted values', function() {
29571 *       expect(element.all(by.css('.htmlComment')).first().getAttribute('innerHTML'))
29572 *           .toBe('<span>Is <i>anyone</i> reading this?</span>');
29573 *     });
29574 *
29575 *     it('should NOT sanitize explicitly trusted values', function() {
29576 *       expect(element(by.id('explicitlyTrustedHtml')).getAttribute('innerHTML')).toBe(
29577 *           '<span onmouseover="this.textContent=&quot;Explicitly trusted HTML bypasses ' +
29578 *           'sanitization.&quot;">Hover over this text.</span>');
29579 *     });
29580 *   });
29581 * </file>
29582 * </example>
29583 *
29584 *
29585 *
29586 * ## Can I disable SCE completely?
29587 *
29588 * Yes, you can.  However, this is strongly discouraged.  SCE gives you a lot of security benefits
29589 * for little coding overhead.  It will be much harder to take an SCE disabled application and
29590 * either secure it on your own or enable SCE at a later stage.  It might make sense to disable SCE
29591 * for cases where you have a lot of existing code that was written before SCE was introduced and
29592 * you're migrating them a module at a time.
29593 *
29594 * That said, here's how you can completely disable SCE:
29595 *
29596 * ```
29597 * angular.module('myAppWithSceDisabledmyApp', []).config(function($sceProvider) {
29598 *   // Completely disable SCE.  For demonstration purposes only!
29599 *   // Do not use in new projects.
29600 *   $sceProvider.enabled(false);
29601 * });
29602 * ```
29603 *
29604 */
29605
29606function $SceProvider() {
29607  var enabled = true;
29608
29609  /**
29610   * @ngdoc method
29611   * @name $sceProvider#enabled
29612   * @kind function
29613   *
29614   * @param {boolean=} value If provided, then enables/disables SCE.
29615   * @return {boolean} true if SCE is enabled, false otherwise.
29616   *
29617   * @description
29618   * Enables/disables SCE and returns the current value.
29619   */
29620  this.enabled = function(value) {
29621    if (arguments.length) {
29622      enabled = !!value;
29623    }
29624    return enabled;
29625  };
29626
29627
29628  /* Design notes on the default implementation for SCE.
29629   *
29630   * The API contract for the SCE delegate
29631   * -------------------------------------
29632   * The SCE delegate object must provide the following 3 methods:
29633   *
29634   * - trustAs(contextEnum, value)
29635   *     This method is used to tell the SCE service that the provided value is OK to use in the
29636   *     contexts specified by contextEnum.  It must return an object that will be accepted by
29637   *     getTrusted() for a compatible contextEnum and return this value.
29638   *
29639   * - valueOf(value)
29640   *     For values that were not produced by trustAs(), return them as is.  For values that were
29641   *     produced by trustAs(), return the corresponding input value to trustAs.  Basically, if
29642   *     trustAs is wrapping the given values into some type, this operation unwraps it when given
29643   *     such a value.
29644   *
29645   * - getTrusted(contextEnum, value)
29646   *     This function should return the a value that is safe to use in the context specified by
29647   *     contextEnum or throw and exception otherwise.
29648   *
29649   * NOTE: This contract deliberately does NOT state that values returned by trustAs() must be
29650   * opaque or wrapped in some holder object.  That happens to be an implementation detail.  For
29651   * instance, an implementation could maintain a registry of all trusted objects by context.  In
29652   * such a case, trustAs() would return the same object that was passed in.  getTrusted() would
29653   * return the same object passed in if it was found in the registry under a compatible context or
29654   * throw an exception otherwise.  An implementation might only wrap values some of the time based
29655   * on some criteria.  getTrusted() might return a value and not throw an exception for special
29656   * constants or objects even if not wrapped.  All such implementations fulfill this contract.
29657   *
29658   *
29659   * A note on the inheritance model for SCE contexts
29660   * ------------------------------------------------
29661   * I've used inheritance and made RESOURCE_URL wrapped types a subtype of URL wrapped types.  This
29662   * is purely an implementation details.
29663   *
29664   * The contract is simply this:
29665   *
29666   *     getTrusted($sce.RESOURCE_URL, value) succeeding implies that getTrusted($sce.URL, value)
29667   *     will also succeed.
29668   *
29669   * Inheritance happens to capture this in a natural way.  In some future, we
vendor: 4,370 bytes, lines 29670-29778
29670   * may not use inheritance anymore.  That is OK because no code outside of
29671   * sce.js and sceSpecs.js would need to be aware of this detail.
29672   */
29673
29674  this.$get = ['$parse', '$sceDelegate', function(
29675                $parse,   $sceDelegate) {
29676    // Support: IE 9-11 only
29677    // Prereq: Ensure that we're not running in IE<11 quirks mode.  In that mode, IE < 11 allow
29678    // the "expression(javascript expression)" syntax which is insecure.
29679    if (enabled && msie < 8) {
29680      throw $sceMinErr('iequirks',
29681        'Strict Contextual Escaping does not support Internet Explorer version < 11 in quirks ' +
29682        'mode.  You can fix this by adding the text <!doctype html> to the top of your HTML ' +
29683        'document.  See http://docs.angularjs.org/api/ng.$sce for more information.');
29684    }
29685
29686    var sce = shallowCopy(SCE_CONTEXTS);
29687
29688    /**
29689     * @ngdoc method
29690     * @name $sce#isEnabled
29691     * @kind function
29692     *
29693     * @return {Boolean} true if SCE is enabled, false otherwise.  If you want to set the value, you
29694     * have to do it at module config time on {@link ng.$sceProvider $sceProvider}.
29695     *
29696     * @description
29697     * Returns a boolean indicating if SCE is enabled.
29698     */
29699    sce.isEnabled = function() {
29700      return enabled;
29701    };
29702    sce.trustAs = $sceDelegate.trustAs;
29703    sce.getTrusted = $sceDelegate.getTrusted;
29704    sce.valueOf = $sceDelegate.valueOf;
29705
29706    if (!enabled) {
29707      sce.trustAs = sce.getTrusted = function(type, value) { return value; };
29708      sce.valueOf = identity;
29709    }
29710
29711    /**
29712     * @ngdoc method
29713     * @name $sce#parseAs
29714     *
29715     * @description
29716     * Converts Angular {@link guide/expression expression} into a function.  This is like {@link
29717     * ng.$parse $parse} and is identical when the expression is a literal constant.  Otherwise, it
29718     * wraps the expression in a call to {@link ng.$sce#getTrusted $sce.getTrusted(*type*,
29719     * *result*)}
29720     *
29721     * @param {string} type The kind of SCE context in which this result will be used.
29722     * @param {string} expression String expression to compile.
29723     * @returns {function(context, locals)} a function which represents the compiled expression:
29724     *
29725     *    * `context` – `{object}` – an object against which any expressions embedded in the strings
29726     *      are evaluated against (typically a scope object).
29727     *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
29728     *      `context`.
29729     */
29730    sce.parseAs = function sceParseAs(type, expr) {
29731      var parsed = $parse(expr);
29732      if (parsed.literal && parsed.constant) {
29733        return parsed;
29734      } else {
29735        return $parse(expr, function(value) {
29736          return sce.getTrusted(type, value);
29737        });
29738      }
29739    };
29740
29741    /**
29742     * @ngdoc method
29743     * @name $sce#trustAs
29744     *
29745     * @description
29746     * Delegates to {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs`}.  As such,
29747     * returns an object that is trusted by angular for use in specified strict contextual
29748     * escaping contexts (such as ng-bind-html, ng-include, any src attribute
29749     * interpolation, any dom event binding attribute interpolation such as for onclick,  etc.)
29750     * that uses the provided value.  See * {@link ng.$sce $sce} for enabling strict contextual
29751     * escaping.
29752     *
29753     * @param {string} type The kind of context in which this value is safe for use.  e.g. url,
29754     *   resourceUrl, html, js and css.
29755     * @param {*} value The value that that should be considered trusted/safe.
29756     * @returns {*} A value that can be used to stand in for the provided `value` in places
29757     * where Angular expects a $sce.trustAs() return value.
29758     */
29759
29760    /**
29761     * @ngdoc method
29762     * @name $sce#trustAsHtml
29763     *
29764     * @description
29765     * Shorthand method.  `$sce.trustAsHtml(value)` →
29766     *     {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.HTML, value)`}
29767     *
29768     * @param {*} value The value to trustAs.
29769     * @returns {*} An object that can be passed to {@link ng.$sce#getTrustedHtml
29770     *     $sce.getTrustedHtml(value)} to obtain the original value.  (privileged directives
29771     *     only accept expressions that are either literal constants or are the
29772     *     return value of {@link ng.$sce#trustAs $sce.trustAs}.)
29773     */
29774
29775    /**
29776     * @ngdoc method
29777     * @name $sce#trustAsUrl
29778     *
29779     * @description
29780     * Shorthand method.  `$sce.trustAsUrl(value)` →
29781     *     {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.URL, value)`}
29782     *
29783     * @param {*} value The value to trustAs.
29784     * @returns {*} An object that can be passed to {@link ng.$sce#getTrustedUrl
29785     *     $sce.getTrustedUrl(value)} to obtain the original value.  (privileged directives
29786     *     only accept expressions that are either literal constants or are the
29787     *     return value of {@link ng.$sce#trustAs $sce.trustAs}.)
29788     */
29789
29790    /**
29791     * @ngdoc method
29792     * @name $sce#trustAsResourceUrl
29793     *
29794     * @description
29795     * Shorthand method.  `$sce.trustAsResourceUrl(value)` →
29796     *     {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.RESOURCE_URL, value)`}
29797     *
29798     * @param {*} value The value to trustAs.
29799     * @returns {*} An object that can be passed to {@link ng.$sce#getTrustedResourceUrl
29800     *     $sce.getTrustedResourceUrl(value)} to obtain the original value.  (privileged directives
29801     *     only accept expressions that are either literal constants or are the return
29802     *     value of {@link ng.$sce#trustAs $sce.trustAs}.)
29803     */
29804
29805    /**
29806     * @ngdoc method
29807     * @name $sce#trustAsJs
29808     *
29809     * @description
29810     * Shorthand method.  `$sce.trustAsJs(value)` →
29811     *     {@link ng.$sceDelegate#trustAs `$sceDelegate.trustAs($sce.JS, value)`}
29812     *
29813     * @param {*} value The value to trustAs.
29814     * @returns {*} An object that can be passed to {@link ng.$sce#getTrustedJs
29815     *     $sce.getTrustedJs(value)} to obtain the original value.  (privileged directives
29816     *     only accept expressions that are either literal constants or are the
29817     *     return value of {@link ng.$sce#trustAs $sce.trustAs}.)
29818     */
29819
29820    /**
29821     * @ngdoc method
29822     * @name $sce#getTrusted
29823     *
29824     * @description
29825     * Delegates to {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted`}.  As such,
29826     * takes the result of a {@link ng.$sce#trustAs `$sce.trustAs`}() call and returns the
29827     * originally supplied value if the queried context type is a supertype of the created type.
29828     * If this condition isn't satisfied, throws an exception.
29829     *
29830     * @param {string} type The kind of context in which this value is to be used.
29831     * @param {*} maybeTrusted The result of a prior {@link ng.$sce#trustAs `$sce.trustAs`}
29832     *                         call.
29833     * @returns {*} The value the was originally provided to
29834     *              {@link ng.$sce#trustAs `$sce.trustAs`} if valid in this context.
29835     *              Otherwise, throws an exception.
29836     */
29837
29838    /**
29839     * @ngdoc method
29840     * @name $sce#getTrustedHtml
29841     *
29842     * @description
29843     * Shorthand method.  `$sce.getTrustedHtml(value)` →
29844     *     {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.HTML, value)`}
29845     *
29846     * @param {*} value The value to pass to `$sce.getTrusted`.
29847     * @returns {*} The return value of `$sce.getTrusted($sce.HTML, value)`
29848     */
29849
29850    /**
29851     * @ngdoc method
29852     * @name $sce#getTrustedCss
29853     *
29854     * @description
29855     * Shorthand method.  `$sce.getTrustedCss(value)` →
29856     *     {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.CSS, value)`}
29857     *
29858     * @param {*} value The value to pass to `$sce.getTrusted`.
29859     * @returns {*} The return value of `$sce.getTrusted($sce.CSS, value)`
29860     */
29861
29862    /**
29863     * @ngdoc method
29864     * @name $sce#getTrustedUrl
29865     *
29866     * @description
29867     * Shorthand method.  `$sce.getTrustedUrl(value)` →
29868     *     {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.URL, value)`}
29869     *
29870     * @param {*} value The value to pass to `$sce.getTrusted`.
29871     * @returns {*} The return value of `$sce.getTrusted($sce.URL, value)`
29872     */
29873
29874    /**
29875     * @ngdoc method
29876     * @name $sce#getTrustedResourceUrl
29877     *
29878     * @description
29879     * Shorthand method.  `$sce.getTrustedResourceUrl(value)` →
29880     *     {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.RESOURCE_URL, value)`}
29881     *
29882     * @param {*} value The value to pass to `$sceDelegate.getTrusted`.
29883     * @returns {*} The return value of `$sce.getTrusted($sce.RESOURCE_URL, value)`
29884     */
29885
29886    /**
29887     * @ngdoc method
29888     * @name $sce#getTrustedJs
29889     *
vendor: 15,074 bytes, lines 29890-30280
29890     * @description
29891     * Shorthand method.  `$sce.getTrustedJs(value)` →
29892     *     {@link ng.$sceDelegate#getTrusted `$sceDelegate.getTrusted($sce.JS, value)`}
29893     *
29894     * @param {*} value The value to pass to `$sce.getTrusted`.
29895     * @returns {*} The return value of `$sce.getTrusted($sce.JS, value)`
29896     */
29897
29898    /**
29899     * @ngdoc method
29900     * @name $sce#parseAsHtml
29901     *
29902     * @description
29903     * Shorthand method.  `$sce.parseAsHtml(expression string)` →
29904     *     {@link ng.$sce#parseAs `$sce.parseAs($sce.HTML, value)`}
29905     *
29906     * @param {string} expression String expression to compile.
29907     * @returns {function(context, locals)} a function which represents the compiled expression:
29908     *
29909     *    * `context` – `{object}` – an object against which any expressions embedded in the strings
29910     *      are evaluated against (typically a scope object).
29911     *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
29912     *      `context`.
29913     */
29914
29915    /**
29916     * @ngdoc method
29917     * @name $sce#parseAsCss
29918     *
29919     * @description
29920     * Shorthand method.  `$sce.parseAsCss(value)` →
29921     *     {@link ng.$sce#parseAs `$sce.parseAs($sce.CSS, value)`}
29922     *
29923     * @param {string} expression String expression to compile.
29924     * @returns {function(context, locals)} a function which represents the compiled expression:
29925     *
29926     *    * `context` – `{object}` – an object against which any expressions embedded in the strings
29927     *      are evaluated against (typically a scope object).
29928     *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
29929     *      `context`.
29930     */
29931
29932    /**
29933     * @ngdoc method
29934     * @name $sce#parseAsUrl
29935     *
29936     * @description
29937     * Shorthand method.  `$sce.parseAsUrl(value)` →
29938     *     {@link ng.$sce#parseAs `$sce.parseAs($sce.URL, value)`}
29939     *
29940     * @param {string} expression String expression to compile.
29941     * @returns {function(context, locals)} a function which represents the compiled expression:
29942     *
29943     *    * `context` – `{object}` – an object against which any expressions embedded in the strings
29944     *      are evaluated against (typically a scope object).
29945     *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
29946     *      `context`.
29947     */
29948
29949    /**
29950     * @ngdoc method
29951     * @name $sce#parseAsResourceUrl
29952     *
29953     * @description
29954     * Shorthand method.  `$sce.parseAsResourceUrl(value)` →
29955     *     {@link ng.$sce#parseAs `$sce.parseAs($sce.RESOURCE_URL, value)`}
29956     *
29957     * @param {string} expression String expression to compile.
29958     * @returns {function(context, locals)} a function which represents the compiled expression:
29959     *
29960     *    * `context` – `{object}` – an object against which any expressions embedded in the strings
29961     *      are evaluated against (typically a scope object).
29962     *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
29963     *      `context`.
29964     */
29965
29966    /**
29967     * @ngdoc method
29968     * @name $sce#parseAsJs
29969     *
29970     * @description
29971     * Shorthand method.  `$sce.parseAsJs(value)` →
29972     *     {@link ng.$sce#parseAs `$sce.parseAs($sce.JS, value)`}
29973     *
29974     * @param {string} expression String expression to compile.
29975     * @returns {function(context, locals)} a function which represents the compiled expression:
29976     *
29977     *    * `context` – `{object}` – an object against which any expressions embedded in the strings
29978     *      are evaluated against (typically a scope object).
29979     *    * `locals` – `{object=}` – local variables context object, useful for overriding values in
29980     *      `context`.
29981     */
29982
29983    // Shorthand delegations.
29984    var parse = sce.parseAs,
29985        getTrusted = sce.getTrusted,
29986        trustAs = sce.trustAs;
29987
29988    forEach(SCE_CONTEXTS, function(enumValue, name) {
29989      var lName = lowercase(name);
29990      sce[snakeToCamel('parse_as_' + lName)] = function(expr) {
29991        return parse(enumValue, expr);
29992      };
29993      sce[snakeToCamel('get_trusted_' + lName)] = function(value) {
29994        return getTrusted(enumValue, value);
29995      };
29996      sce[snakeToCamel('trust_as_' + lName)] = function(value) {
29997        return trustAs(enumValue, value);
29998      };
29999    });
30000
30001    return sce;
30002  }];
30003}
30004
30005/* exported $SnifferProvider */
30006
30007/**
30008 * !!! This is an undocumented "private" service !!!
30009 *
30010 * @name $sniffer
30011 * @requires $window
30012 * @requires $document
30013 * @this
30014 *
30015 * @property {boolean} history Does the browser support html5 history api ?
30016 * @property {boolean} transitions Does the browser support CSS transition events ?
30017 * @property {boolean} animations Does the browser support CSS animation events ?
30018 *
30019 * @description
30020 * This is very simple implementation of testing browser's features.
30021 */
30022function $SnifferProvider() {
30023  this.$get = ['$window', '$document', function($window, $document) {
30024    var eventSupport = {},
30025        // Chrome Packaged Apps are not allowed to access `history.pushState`.
30026        // If not sandboxed, they can be detected by the presence of `chrome.app.runtime`
30027        // (see https://developer.chrome.com/apps/api_index). If sandboxed, they can be detected by
30028        // the presence of an extension runtime ID and the absence of other Chrome runtime APIs
30029        // (see https://developer.chrome.com/apps/manifest/sandbox).
30030        // (NW.js apps have access to Chrome APIs, but do support `history`.)
30031        isNw = $window.nw && $window.nw.process,
30032        isChromePackagedApp =
30033            !isNw &&
30034            $window.chrome &&
30035            ($window.chrome.app && $window.chrome.app.runtime ||
30036                !$window.chrome.app && $window.chrome.runtime && $window.chrome.runtime.id),
30037        hasHistoryPushState = !isChromePackagedApp && $window.history && $window.history.pushState,
30038        android =
30039          toInt((/android (\d+)/.exec(lowercase(($window.navigator || {}).userAgent)) || [])[1]),
30040        boxee = /Boxee/i.test(($window.navigator || {}).userAgent),
30041        document = $document[0] || {},
30042        bodyStyle = document.body && document.body.style,
30043        transitions = false,
30044        animations = false;
30045
30046    if (bodyStyle) {
30047      // Support: Android <5, Blackberry Browser 10, default Chrome in Android 4.4.x
30048      // Mentioned browsers need a -webkit- prefix for transitions & animations.
30049      transitions = !!('transition' in bodyStyle || 'webkitTransition' in bodyStyle);
30050      animations = !!('animation' in bodyStyle || 'webkitAnimation' in bodyStyle);
30051    }
30052
30053
30054    return {
30055      // Android has history.pushState, but it does not update location correctly
30056      // so let's not use the history API at all.
30057      // http://code.google.com/p/android/issues/detail?id=17471
30058      // https://github.com/angular/angular.js/issues/904
30059
30060      // older webkit browser (533.9) on Boxee box has exactly the same problem as Android has
30061      // so let's not use the history API also
30062      // We are purposefully using `!(android < 4)` to cover the case when `android` is undefined
30063      history: !!(hasHistoryPushState && !(android < 4) && !boxee),
30064      hasEvent: function(event) {
30065        // Support: IE 9-11 only
30066        // IE9 implements 'input' event it's so fubared that we rather pretend that it doesn't have
30067        // it. In particular the event is not fired when backspace or delete key are pressed or
30068        // when cut operation is performed.
30069        // IE10+ implements 'input' event but it erroneously fires under various situations,
30070        // e.g. when placeholder changes, or a form is focused.
30071        if (event === 'input' && msie) return false;
30072
30073        if (isUndefined(eventSupport[event])) {
30074          var divElm = document.createElement('div');
30075          eventSupport[event] = 'on' + event in divElm;
30076        }
30077
30078        return eventSupport[event];
30079      },
30080      csp: csp(),
30081      transitions: transitions,
30082      animations: animations,
30083      android: android
30084    };
30085  }];
30086}
30087
30088var $templateRequestMinErr = minErr('$compile');
30089
30090/**
30091 * @ngdoc provider
30092 * @name $templateRequestProvider
30093 * @this
30094 *
30095 * @description
30096 * Used to configure the options passed to the {@link $http} service when making a template request.
30097 *
30098 * For example, it can be used for specifying the "Accept" header that is sent to the server, when
30099 * requesting a template.
30100 */
30101function $TemplateRequestProvider() {
30102
30103  var httpOptions;
30104
30105  /**
30106   * @ngdoc method
30107   * @name $templateRequestProvider#httpOptions
30108   * @description
30109   * The options to be passed to the {@link $http} service when making the request.
30110   * You can use this to override options such as the "Accept" header for template requests.
30111   *
30112   * The {@link $templateRequest} will set the `cache` and the `transformResponse` properties of the
30113   * options if not overridden here.
30114   *
30115   * @param {string=} value new value for the {@link $http} options.
30116   * @returns {string|self} Returns the {@link $http} options when used as getter and self if used as setter.
30117   */
30118  this.httpOptions = function(val) {
30119    if (val) {
30120      httpOptions = val;
30121      return this;
30122    }
30123    return httpOptions;
30124  };
30125
30126  /**
30127   * @ngdoc service
30128   * @name $templateRequest
30129   *
30130   * @description
30131   * The `$templateRequest` service runs security checks then downloads the provided template using
30132   * `$http` and, upon success, stores the contents inside of `$templateCache`. If the HTTP request
30133   * fails or the response data of the HTTP request is empty, a `$compile` error will be thrown (the
30134   * exception can be thwarted by setting the 2nd parameter of the function to true). Note that the
30135   * contents of `$templateCache` are trusted, so the call to `$sce.getTrustedUrl(tpl)` is omitted
30136   * when `tpl` is of type string and `$templateCache` has the matching entry.
30137   *
30138   * If you want to pass custom options to the `$http` service, such as setting the Accept header you
30139   * can configure this via {@link $templateRequestProvider#httpOptions}.
30140   *
30141   * @param {string|TrustedResourceUrl} tpl The HTTP request template URL
30142   * @param {boolean=} ignoreRequestError Whether or not to ignore the exception when the request fails or the template is empty
30143   *
30144   * @return {Promise} a promise for the HTTP response data of the given URL.
30145   *
30146   * @property {number} totalPendingRequests total amount of pending template requests being downloaded.
30147   */
30148  this.$get = ['$exceptionHandler', '$templateCache', '$http', '$q', '$sce',
30149    function($exceptionHandler, $templateCache, $http, $q, $sce) {
30150
30151      function handleRequestFn(tpl, ignoreRequestError) {
30152        handleRequestFn.totalPendingRequests++;
30153
30154        // We consider the template cache holds only trusted templates, so
30155        // there's no need to go through whitelisting again for keys that already
30156        // are included in there. This also makes Angular accept any script
30157        // directive, no matter its name. However, we still need to unwrap trusted
30158        // types.
30159        if (!isString(tpl) || isUndefined($templateCache.get(tpl))) {
30160          tpl = $sce.getTrustedResourceUrl(tpl);
30161        }
30162
30163        var transformResponse = $http.defaults && $http.defaults.transformResponse;
30164
30165        if (isArray(transformResponse)) {
30166          transformResponse = transformResponse.filter(function(transformer) {
30167            return transformer !== defaultHttpResponseTransform;
30168          });
30169        } else if (transformResponse === defaultHttpResponseTransform) {
30170          transformResponse = null;
30171        }
30172
30173        return $http.get(tpl, extend({
30174            cache: $templateCache,
30175            transformResponse: transformResponse
30176          }, httpOptions))
30177          .finally(function() {
30178            handleRequestFn.totalPendingRequests--;
30179          })
30180          .then(function(response) {
30181            $templateCache.put(tpl, response.data);
30182            return response.data;
30183          }, handleError);
30184
30185        function handleError(resp) {
30186          if (!ignoreRequestError) {
30187            resp = $templateRequestMinErr('tpload',
30188                'Failed to load template: {0} (HTTP status: {1} {2})',
30189                tpl, resp.status, resp.statusText);
30190
30191            $exceptionHandler(resp);
30192          }
30193
30194          return $q.reject(resp);
30195        }
30196      }
30197
30198      handleRequestFn.totalPendingRequests = 0;
30199
30200      return handleRequestFn;
30201    }
30202  ];
30203}
30204
30205/** @this */
30206function $$TestabilityProvider() {
30207  this.$get = ['$rootScope', '$browser', '$location',
30208       function($rootScope,   $browser,   $location) {
30209
30210    /**
30211     * @name $testability
30212     *
30213     * @description
30214     * The private $$testability service provides a collection of methods for use when debugging
30215     * or by automated test and debugging tools.
30216     */
30217    var testability = {};
30218
30219    /**
30220     * @name $$testability#findBindings
30221     *
30222     * @description
30223     * Returns an array of elements that are bound (via ng-bind or {{}})
30224     * to expressions matching the input.
30225     *
30226     * @param {Element} element The element root to search from.
30227     * @param {string} expression The binding expression to match.
30228     * @param {boolean} opt_exactMatch If true, only returns exact matches
30229     *     for the expression. Filters and whitespace are ignored.
30230     */
30231    testability.findBindings = function(element, expression, opt_exactMatch) {
30232      var bindings = element.getElementsByClassName('ng-binding');
30233      var matches = [];
30234      forEach(bindings, function(binding) {
30235        var dataBinding = angular.element(binding).data('$binding');
30236        if (dataBinding) {
30237          forEach(dataBinding, function(bindingName) {
30238            if (opt_exactMatch) {
30239              var matcher = new RegExp('(^|\\s)' + escapeForRegexp(expression) + '(\\s|\\||$)');
30240              if (matcher.test(bindingName)) {
30241                matches.push(binding);
30242              }
30243            } else {
30244              if (bindingName.indexOf(expression) !== -1) {
30245                matches.push(binding);
30246              }
30247            }
30248          });
30249        }
30250      });
30251      return matches;
30252    };
30253
30254    /**
30255     * @name $$testability#findModels
30256     *
30257     * @description
30258     * Returns an array of elements that are two-way found via ng-model to
30259     * expressions matching the input.
30260     *
30261     * @param {Element} element The element root to search from.
30262     * @param {string} expression The model expression to match.
30263     * @param {boolean} opt_exactMatch If true, only returns exact matches
30264     *     for the expression.
30265     */
30266    testability.findModels = function(element, expression, opt_exactMatch) {
30267      var prefixes = ['ng-', 'data-ng-', 'ng\\:'];
30268      for (var p = 0; p < prefixes.length; ++p) {
30269        var attributeEquals = opt_exactMatch ? '=' : '*=';
30270        var selector = '[' + prefixes[p] + 'model' + attributeEquals + '"' + expression + '"]';
30271        var elements = element.querySelectorAll(selector);
30272        if (elements.length) {
30273          return elements;
30274        }
30275      }
30276    };
30277
30278    /**
30279     * @name $$testability#getLocation
30280     *
30281     * @description
30282     * Shortcut for getting the location in a browser agnostic way. Returns
30283     *     the path, search, and hash. (e.g. /path?a=b#hash)
30284     */
30285    testability.getLocation = function() {
30286      return $location.url();
30287    };
30288
30289    /**
30290     * @name $$testability#setLocation
30291     *
30292     * @description
30293     * Shortcut for navigating to a location without doing a full page reload.
30294     *
30295     * @param {string} url The location url (path, search and hash,
30296     *     e.g. /path?a=b#hash) to go to.
30297     */
30298    testability.setLocation = function(url) {
30299      if (url !== $location.url()) {
30300        $location.url(url);
30301        $rootScope.$digest();
30302      }
30303    };
30304
30305    /**
30306     * @name $$testability#whenStable
30307     *
30308     * @description
30309     * Calls the callback when $timeout and $http requests are completed.
30310     *
30311     * @param {function} callback
30312     */
30313    testability.whenStable = function(callback) {
30314      $browser.notifyWhenNoOutstandingRequests(callback);
30315    };
30316
30317    return testability;
30318  }];
30319}
30320
30321/** @this */
30322function $TimeoutProvider() {
30323  this.$get = ['$rootScope', '$browser', '$q', '$$q', '$exceptionHandler',
30324       function($rootScope,   $browser,   $q,   $$q,   $exceptionHandler) {
30325
30326    var deferreds = {};
30327
30328
30329     /**
30330      * @ngdoc service
30331      * @name $timeout
30332      *
30333      * @description
30334      * Angular's wrapper for `window.setTimeout`. The `fn` function is wrapped into a try/catch
30335      * block and delegates any exceptions to
30336      * {@link ng.$exceptionHandler $exceptionHandler} service.
30337      *
30338      * The return value of calling `$timeout` is a promise, which will be resolved when
30339      * the delay has passed and the timeout function, if provided, is executed.
30340      *
30341      * To cancel a timeout request, call `$timeout.cancel(promise)`.
30342      *
30343      * In tests you can use {@link ngMock.$timeout `$timeout.flush()`} to
30344      * synchronously flush the queue of deferred functions.
30345      *
30346      * If you only want a promise that will be resolved after some specified delay
30347      * then you can call `$timeout` without the `fn` function.
30348      *
30349      * @param {function()=} fn A function, whose execution should be delayed.
30350      * @param {number=} [delay=0] Delay in milliseconds.
30351      * @param {boolean=} [invokeApply=true] If set to `false` skips model dirty checking, otherwise
30352      *   will invoke `fn` within the {@link ng.$rootScope.Scope#$apply $apply} block.
30353      * @param {...*=} Pass additional parameters to the executed function.
30354      * @returns {Promise} Promise that will be resolved when the timeout is reached. The promise
30355      *   will be resolved with the return value of the `fn` function.
30356      *
30357      */
30358    function timeout(fn, delay, invokeApply) {
30359      if (!isFunction(fn)) {
30360        invokeApply = delay;
30361        delay = fn;
30362        fn = noop;
30363      }
30364
30365      var args = sliceArgs(arguments, 3),
30366          skipApply = (isDefined(invokeApply) && !invokeApply),
30367          deferred = (skipApply ? $$q : $q).defer(),
30368          promise = deferred.promise,
30369          timeoutId;
30370
30371      timeoutId = $browser.defer(function() {
30372        try {
30373          deferred.resolve(fn.apply(null, args));
30374        } catch (e) {
30375          deferred.reject(e);
30376          $exceptionHandler(e);
30377        } finally {
30378          delete deferreds[promise.$$timeoutId];
30379        }
30380
30381        if (!skipApply) $rootScope.$apply();
30382      }, delay);
30383
30384      promise.$$timeoutId = timeoutId;
30385      deferreds[timeoutId] = deferred;
30386
30387      return promise;
30388    }
30389
30390
30391     /**
30392      * @ngdoc method
30393      * @name $timeout#cancel
30394      *
30395      * @description
30396      * Cancels a task associated with the `promise`. As a result of this, the promise will be
30397      * resolved with a rejection.
30398      *
30399      * @param {Promise=} promise Promise returned by the `$timeout` function.
30400      * @returns {boolean} Returns `true` if the task hasn't executed yet and was successfully
30401      *   canceled.
30402      */
30403    timeout.cancel = function(promise) {
30404      if (promise && promise.$$timeoutId in deferreds) {
30405        // Timeout cancels should not report an unhandled promise.
30406        deferreds[promise.$$timeoutId].promise.catch(noop);
30407        deferreds[promise.$$timeoutId].reject('canceled');
30408        delete deferreds[promise.$$timeoutId];
30409        return $browser.defer.cancel(promise.$$timeoutId);
30410      }
30411      return false;
vendor: 5,388 bytes, lines 30412-30535
30412    };
30413
30414    return timeout;
30415  }];
30416}
30417
30418// NOTE:  The usage of window and document instead of $window and $document here is
30419// deliberate.  This service depends on the specific behavior of anchor nodes created by the
30420// browser (resolving and parsing URLs) that is unlikely to be provided by mock objects and
30421// cause us to break tests.  In addition, when the browser resolves a URL for XHR, it
30422// doesn't know about mocked locations and resolves URLs to the real document - which is
30423// exactly the behavior needed here.  There is little value is mocking these out for this
30424// service.
30425var urlParsingNode = window.document.createElement('a');
30426var originUrl = urlResolve(window.location.href);
30427
30428
30429/**
30430 *
30431 * Implementation Notes for non-IE browsers
30432 * ----------------------------------------
30433 * Assigning a URL to the href property of an anchor DOM node, even one attached to the DOM,
30434 * results both in the normalizing and parsing of the URL.  Normalizing means that a relative
30435 * URL will be resolved into an absolute URL in the context of the application document.
30436 * Parsing means that the anchor node's host, hostname, protocol, port, pathname and related
30437 * properties are all populated to reflect the normalized URL.  This approach has wide
30438 * compatibility - Safari 1+, Mozilla 1+ etc.  See
30439 * http://www.aptana.com/reference/html/api/HTMLAnchorElement.html
30440 *
30441 * Implementation Notes for IE
30442 * ---------------------------
30443 * IE <= 10 normalizes the URL when assigned to the anchor node similar to the other
30444 * browsers.  However, the parsed components will not be set if the URL assigned did not specify
30445 * them.  (e.g. if you assign a.href = "foo", then a.protocol, a.host, etc. will be empty.)  We
30446 * work around that by performing the parsing in a 2nd step by taking a previously normalized
30447 * URL (e.g. by assigning to a.href) and assigning it a.href again.  This correctly populates the
30448 * properties such as protocol, hostname, port, etc.
30449 *
30450 * References:
30451 *   http://developer.mozilla.org/en-US/docs/Web/API/HTMLAnchorElement
30452 *   http://www.aptana.com/reference/html/api/HTMLAnchorElement.html
30453 *   http://url.spec.whatwg.org/#urlutils
30454 *   https://github.com/angular/angular.js/pull/2902
30455 *   http://james.padolsey.com/javascript/parsing-urls-with-the-dom/
30456 *
30457 * @kind function
30458 * @param {string} url The URL to be parsed.
30459 * @description Normalizes and parses a URL.
30460 * @returns {object} Returns the normalized URL as a dictionary.
30461 *
30462 *   | member name   | Description    |
30463 *   |---------------|----------------|
30464 *   | href          | A normalized version of the provided URL if it was not an absolute URL |
30465 *   | protocol      | The protocol including the trailing colon                              |
30466 *   | host          | The host and port (if the port is non-default) of the normalizedUrl    |
30467 *   | search        | The search params, minus the question mark                             |
30468 *   | hash          | The hash string, minus the hash symbol
30469 *   | hostname      | The hostname
30470 *   | port          | The port, without ":"
30471 *   | pathname      | The pathname, beginning with "/"
30472 *
30473 */
30474function urlResolve(url) {
30475  var href = url;
30476
30477  // Support: IE 9-11 only
30478  if (msie) {
30479    // Normalize before parse.  Refer Implementation Notes on why this is
30480    // done in two steps on IE.
30481    urlParsingNode.setAttribute('href', href);
30482    href = urlParsingNode.href;
30483  }
30484
30485  urlParsingNode.setAttribute('href', href);
30486
30487  // urlParsingNode provides the UrlUtils interface - http://url.spec.whatwg.org/#urlutils
30488  return {
30489    href: urlParsingNode.href,
30490    protocol: urlParsingNode.protocol ? urlParsingNode.protocol.replace(/:$/, '') : '',
30491    host: urlParsingNode.host,
30492    search: urlParsingNode.search ? urlParsingNode.search.replace(/^\?/, '') : '',
30493    hash: urlParsingNode.hash ? urlParsingNode.hash.replace(/^#/, '') : '',
30494    hostname: urlParsingNode.hostname,
30495    port: urlParsingNode.port,
30496    pathname: (urlParsingNode.pathname.charAt(0) === '/')
30497      ? urlParsingNode.pathname
30498      : '/' + urlParsingNode.pathname
30499  };
30500}
30501
30502/**
30503 * Parse a request URL and determine whether this is a same-origin request as the application document.
30504 *
30505 * @param {string|object} requestUrl The url of the request as a string that will be resolved
30506 * or a parsed URL object.
30507 * @returns {boolean} Whether the request is for the same origin as the application document.
30508 */
30509function urlIsSameOrigin(requestUrl) {
30510  var parsed = (isString(requestUrl)) ? urlResolve(requestUrl) : requestUrl;
30511  return (parsed.protocol === originUrl.protocol &&
30512          parsed.host === originUrl.host);
30513}
30514
30515/**
30516 * @ngdoc service
30517 * @name $window
30518 * @this
30519 *
30520 * @description
30521 * A reference to the browser's `window` object. While `window`
30522 * is globally available in JavaScript, it causes testability problems, because
30523 * it is a global variable. In angular we always refer to it through the
30524 * `$window` service, so it may be overridden, removed or mocked for testing.
30525 *
30526 * Expressions, like the one defined for the `ngClick` directive in the example
30527 * below, are evaluated with respect to the current scope.  Therefore, there is
30528 * no risk of inadvertently coding in a dependency on a global value in such an
30529 * expression.
30530 *
30531 * @example
30532   <example module="windowExample" name="window-service">
30533     <file name="index.html">
30534       <script>
30535         angular.module('windowExample', [])
30536           .controller('ExampleController', ['$scope', '$window', function($scope, $window) {
30537             $scope.greeting = 'Hello, World!';
30538             $scope.doGreeting = function(greeting) {
30539               $window.alert(greeting);
30540             };
30541           }]);
30542       </script>
30543       <div ng-controller="ExampleController">
30544         <input type="text" ng-model="greeting" aria-label="greeting" />
30545         <button ng-click="doGreeting(greeting)">ALERT</button>
30546       </div>
30547     </file>
30548     <file name="protractor.js" type="protractor">
30549      it('should display the greeting in the input box', function() {
30550       element(by.model('greeting')).sendKeys('Hello, E2E Tests');
30551       // If we click the button it will block the test runner
30552       // element(':button').click();
30553      });
30554     </file>
30555   </example>
30556 */
30557function $WindowProvider() {
30558  this.$get = valueFn(window);
30559}
30560
30561/**
30562 * @name $$cookieReader
30563 * @requires $document
30564 *
30565 * @description
30566 * This is a private service for reading cookies used by $http and ngCookies
30567 *
30568 * @return {Object} a key/value map of the current cookies
30569 */
30570function $$CookieReader($document) {
30571  var rawDocument = $document[0] || {};
30572  var lastCookies = {};
30573  var lastCookieString = '';
30574
30575  function safeGetCookie(rawDocument) {
30576    try {
30577      return rawDocument.cookie || '';
30578    } catch (e) {
30579      return '';
30580    }
30581  }
30582
30583  function safeDecodeURIComponent(str) {
30584    try {
30585      return decodeURIComponent(str);
30586    } catch (e) {
30587      return str;
30588    }
30589  }
30590
30591  return function() {
30592    var cookieArray, cookie, i, index, name;
30593    var currentCookieString = safeGetCookie(rawDocument);
30594
30595    if (currentCookieString !== lastCookieString) {
30596      lastCookieString = currentCookieString;
30597      cookieArray = lastCookieString.split('; ');
30598      lastCookies = {};
30599
30600      for (i = 0; i < cookieArray.length; i++) {
30601        cookie = cookieArray[i];
30602        index = cookie.indexOf('=');
30603        if (index > 0) { //ignore nameless cookies
30604          name = safeDecodeURIComponent(cookie.substring(0, index));
30605          // the first value that is seen for a cookie is the most
30606          // specific one.  values for the same cookie name that
30607          // follow are for less specific paths.
30608          if (isUndefined(lastCookies[name])) {
30609            lastCookies[name] = safeDecodeURIComponent(cookie.substring(index + 1));
30610          }
30611        }
30612      }
30613    }
30614    return lastCookies;
30615  };
30616}
30617
30618$$CookieReader.$inject = ['$document'];
30619
30620/** @this */
30621function $$CookieReaderProvider() {
30622  this.$get = $$CookieReader;
30623}
30624
30625/* global currencyFilter: true,
30626 dateFilter: true,
30627 filterFilter: true,
30628 jsonFilter: true,
30629 limitToFilter: true,
30630 lowercaseFilter: true,
30631 numberFilter: true,
30632 orderByFilter: true,
30633 uppercaseFilter: true,
30634 */
30635
30636/**
30637 * @ngdoc provider
30638 * @name $filterProvider
30639 * @description
30640 *
30641 * Filters are just functions which transform input to an output. However filters need to be
30642 * Dependency Injected. To achieve this a filter definition consists of a factory function which is
30643 * annotated with dependencies and is responsible for creating a filter function.
30644 *
30645 * <div class="alert alert-warning">
30646 * **Note:** Filter names must be valid angular {@link expression} identifiers, such as `uppercase` or `orderBy`.
30647 * Names with special characters, such as hyphens and dots, are not allowed. If you wish to namespace
30648 * your filters, then you can use capitalization (`myappSubsectionFilterx`) or underscores
30649 * (`myapp_subsection_filterx`).
30650 * </div>
30651 *
30652 * ```js
30653 *   // Filter registration
30654 *   function MyModule($provide, $filterProvider) {
30655 *     // create a service to demonstrate injection (not always needed)
30656 *     $provide.value('greet', function(name){
30657 *       return 'Hello ' + name + '!';
30658 *     });
30659 *
30660 *     // register a filter factory which uses the
30661 *     // greet service to demonstrate DI.
30662 *     $filterProvider.register('greet', function(greet){
30663 *       // return the filter function which uses the greet service
30664 *       // to generate salutation
30665 *       return function(text) {
30666 *         // filters need to be forgiving so check input validity
30667 *         return text && greet(text) || text;
30668 *       };
30669 *     });
30670 *   }
30671 * ```
30672 *
30673 * The filter function is registered with the `$injector` under the filter name suffix with
30674 * `Filter`.
30675 *
30676 * ```js
30677 *   it('should be the same instance', inject(
30678 *     function($filterProvider) {
30679 *       $filterProvider.register('reverse', function(){
30680 *         return ...;
30681 *       });
30682 *     },
30683 *     function($filter, reverseFilter) {
30684 *       expect($filter('reverse')).toBe(reverseFilter);
30685 *     });
30686 * ```
30687 *
30688 *
30689 * For more information about how angular filters work, and how to create your own filters, see
30690 * {@link guide/filter Filters} in the Angular Developer Guide.
30691 */
30692
30693/**
30694 * @ngdoc service
30695 * @name $filter
30696 * @kind function
30697 * @description
30698 * Filters are used for formatting data displayed to the user.
30699 *
30700 * They can be used in view templates, controllers or services.Angular comes
30701 * with a collection of [built-in filters](api/ng/filter), but it is easy to
30702 * define your own as well.
30703 *
30704 * The general syntax in templates is as follows:
30705 *
30706 * ```html
30707 * {{ expression [| filter_name[:parameter_value] ... ] }}
30708 * ```
30709 *
30710 * @param {String} name Name of the filter function to retrieve
30711 * @return {Function} the filter function
30712 * @example
30713   <example name="$filter" module="filterExample">
30714     <file name="index.html">
30715       <div ng-controller="MainCtrl">
30716        <h3>{{ originalText }}</h3>
30717        <h3>{{ filteredText }}</h3>
30718       </div>
30719     </file>
30720
30721     <file name="script.js">
30722      angular.module('filterExample', [])
30723      .controller('MainCtrl', function($scope, $filter) {
30724        $scope.originalText = 'hello';
30725        $scope.filteredText = $filter('uppercase')($scope.originalText);
30726      });
30727     </file>
30728   </example>
30729  */
30730$FilterProvider.$inject = ['$provide'];
30731/** @this */
30732function $FilterProvider($provide) {
30733  var suffix = 'Filter';
30734
30735  /**
30736   * @ngdoc method
30737   * @name $filterProvider#register
30738   * @param {string|Object} name Name of the filter function, or an object map of filters where
30739   *    the keys are the filter names and the values are the filter factories.
30740   *
30741   *    <div class="alert alert-warning">
30742   *    **Note:** Filter names must be valid angular {@link expression} identifiers, such as `uppercase` or `orderBy`.
30743   *    Names with special characters, such as hyphens and dots, are not allowed. If you wish to namespace
30744   *    your filters, then you can use capitalization (`myappSubsectionFilterx`) or underscores
30745   *    (`myapp_subsection_filterx`).
30746   *    </div>
30747    * @param {Function} factory If the first argument was a string, a factory function for the filter to be registered.
30748   * @returns {Object} Registered filter instance, or if a map of filters was provided then a map
30749   *    of the registered filter instances.
30750   */
30751  function register(name, factory) {
30752    if (isObject(name)) {
30753      var filters = {};
30754      forEach(name, function(filter, key) {
30755        filters[key] = register(key, filter);
30756      });
30757      return filters;
30758    } else {
30759      return $provide.factory(name + suffix, factory);
30760    }
30761  }
30762  this.register = register;
30763
30764  this.$get = ['$injector', function($injector) {
30765    return function(name) {
30766      return $injector.get(name + suffix);
30767    };
30768  }];
30769
30770  ////////////////////////////////////////
30771
30772  /* global
30773    currencyFilter: false,
30774    dateFilter: false,
30775    filterFilter: false,
30776    jsonFilter: false,
30777    limitToFilter: false,
30778    lowercaseFilter: false,
30779    numberFilter: false,
30780    orderByFilter: false,
30781    uppercaseFilter: false
30782  */
30783
30784  register('currency', currencyFilter);
30785  register('date', dateFilter);
30786  register('filter', filterFilter);
30787  register('json', jsonFilter);
30788  register('limitTo', limitToFilter);
30789  register('lowercase', lowercaseFilter);
30790  register('number', numberFilter);
30791  register('orderBy', orderByFilter);
30792  register('uppercase', uppercaseFilter);
30793}
30794
30795/**
30796 * @ngdoc filter
30797 * @name filter
30798 * @kind function
30799 *
30800 * @description
30801 * Selects a subset of items from `array` and returns it as a new array.
30802 *
30803 * @param {Array} array The source array.
30804 * <div class="alert alert-info">
30805 *   **Note**: If the array contains objects that reference themselves, filtering is not possible.
30806 * </div>
30807 * @param {string|Object|function()} expression The predicate to be used for selecting items from
30808 *   `array`.
30809 *
30810 *   Can be one of:
30811 *
30812 *   - `string`: The string is used for matching against the contents of the `array`. All strings or
30813 *     objects with string properties in `array` that match this string will be returned. This also
30814 *     applies to nested object properties.
30815 *     The predicate can be negated by prefixing the string with `!`.
30816 *
30817 *   - `Object`: A pattern object can be used to filter specific properties on objects contained
30818 *     by `array`. For example `{name:"M", phone:"1"}` predicate will return an array of items
30819 *     which have property `name` containing "M" and property `phone` containing "1". A special
30820 *     property name (`$` by default) can be used (e.g. as in `{$: "text"}`) to accept a match
30821 *     against any property of the object or its nested object properties. That's equivalent to the
30822 *     simple substring match with a `string` as described above. The special property name can be
30823 *     overwritten, using the `anyPropertyKey` parameter.
30824 *     The predicate can be negated by prefixing the string with `!`.
30825 *     For example `{name: "!M"}` predicate will return an array of items which have property `name`
30826 *     not containing "M".
30827 *
30828 *     Note that a named property will match properties on the same level only, while the special
30829 *     `$` property will match properties on the same level or deeper. E.g. an array item like
30830 *     `{name: {first: 'John', last: 'Doe'}}` will **not** be matched by `{name: 'John'}`, but
30831 *     **will** be matched by `{$: 'John'}`.
30832 *
30833 *   - `function(value, index, array)`: A predicate function can be used to write arbitrary filters.
30834 *     The function is called for each element of the array, with the element, its index, and
30835 *     the entire array itself as arguments.
30836 *
30837 *     The final result is an array of those elements that the predicate returned true for.
30838 *
30839 * @param {function(actual, expected)|true|false} [comparator] Comparator which is used in
30840 *     determining if the expected value (from the filter expression) and actual value (from
30841 *     the object in the array) should be considered a match
vendor: 10,736 bytes, lines 30841-31129
30841.
30842 *
30843 *   Can be one of:
30844 *
30845 *   - `function(actual, expected)`:
30846 *     The function will be given the object value and the predicate value to compare and
30847 *     should return true if both values should be considered equal.
30848 *
30849 *   - `true`: A shorthand for `function(actual, expected) { return angular.equals(actual, expected)}`.
30850 *     This is essentially strict comparison of expected and actual.
30851 *
30852 *   - `false`: A short hand for a function which will look for a substring match in a case
30853 *     insensitive way. Primitive values are converted to strings. Objects are not compared against
30854 *     primitives, unless they have a custom `toString` method (e.g. `Date` objects).
30855 *
30856 *
30857 *   Defaults to `false`.
30858 *
30859 * @param {string} [anyPropertyKey] The special property name that matches against any property.
30860 *     By default `$`.
30861 *
30862 * @example
30863   <example name="filter-filter">
30864     <file name="index.html">
30865       <div ng-init="friends = [{name:'John', phone:'555-1276'},
30866                                {name:'Mary', phone:'800-BIG-MARY'},
30867                                {name:'Mike', phone:'555-4321'},
30868                                {name:'Adam', phone:'555-5678'},
30869                                {name:'Julie', phone:'555-8765'},
30870                                {name:'Juliette', phone:'555-5678'}]"></div>
30871
30872       <label>Search: <input ng-model="searchText"></label>
30873       <table id="searchTextResults">
30874         <tr><th>Name</th><th>Phone</th></tr>
30875         <tr ng-repeat="friend in friends | filter:searchText">
30876           <td>{{friend.name}}</td>
30877           <td>{{friend.phone}}</td>
30878         </tr>
30879       </table>
30880       <hr>
30881       <label>Any: <input ng-model="search.$"></label> <br>
30882       <label>Name only <input ng-model="search.name"></label><br>
30883       <label>Phone only <input ng-model="search.phone"></label><br>
30884       <label>Equality <input type="checkbox" ng-model="strict"></label><br>
30885       <table id="searchObjResults">
30886         <tr><th>Name</th><th>Phone</th></tr>
30887         <tr ng-repeat="friendObj in friends | filter:search:strict">
30888           <td>{{friendObj.name}}</td>
30889           <td>{{friendObj.phone}}</td>
30890         </tr>
30891       </table>
30892     </file>
30893     <file name="protractor.js" type="protractor">
30894       var expectFriendNames = function(expectedNames, key) {
30895         element.all(by.repeater(key + ' in friends').column(key + '.name')).then(function(arr) {
30896           arr.forEach(function(wd, i) {
30897             expect(wd.getText()).toMatch(expectedNames[i]);
30898           });
30899         });
30900       };
30901
30902       it('should search across all fields when filtering with a string', function() {
30903         var searchText = element(by.model('searchText'));
30904         searchText.clear();
30905         searchText.sendKeys('m');
30906         expectFriendNames(['Mary', 'Mike', 'Adam'], 'friend');
30907
30908         searchText.clear();
30909         searchText.sendKeys('76');
30910         expectFriendNames(['John', 'Julie'], 'friend');
30911       });
30912
30913       it('should search in specific fields when filtering with a predicate object', function() {
30914         var searchAny = element(by.model('search.$'));
30915         searchAny.clear();
30916         searchAny.sendKeys('i');
30917         expectFriendNames(['Mary', 'Mike', 'Julie', 'Juliette'], 'friendObj');
30918       });
30919       it('should use a equal comparison when comparator is true', function() {
30920         var searchName = element(by.model('search.name'));
30921         var strict = element(by.model('strict'));
30922         searchName.clear();
30923         searchName.sendKeys('Julie');
30924         strict.click();
30925         expectFriendNames(['Julie'], 'friendObj');
30926       });
30927     </file>
30928   </example>
30929 */
30930
30931function filterFilter() {
30932  return function(array, expression, comparator, anyPropertyKey) {
30933    if (!isArrayLike(array)) {
30934      if (array == null) {
30935        return array;
30936      } else {
30937        throw minErr('filter')('notarray', 'Expected array but received: {0}', array);
30938      }
30939    }
30940
30941    anyPropertyKey = anyPropertyKey || '$';
30942    var expressionType = getTypeForFilter(expression);
30943    var predicateFn;
30944    var matchAgainstAnyProp;
30945
30946    switch (expressionType) {
30947      case 'function':
30948        predicateFn = expression;
30949        break;
30950      case 'boolean':
30951      case 'null':
30952      case 'number':
30953      case 'string':
30954        matchAgainstAnyProp = true;
30955        // falls through
30956      case 'object':
30957        predicateFn = createPredicateFn(expression, comparator, anyPropertyKey, matchAgainstAnyProp);
30958        break;
30959      default:
30960        return array;
30961    }
30962
30963    return Array.prototype.filter.call(array, predicateFn);
30964  };
30965}
30966
30967// Helper functions for `filterFilter`
30968function createPredicateFn(expression, comparator, anyPropertyKey, matchAgainstAnyProp) {
30969  var shouldMatchPrimitives = isObject(expression) && (anyPropertyKey in expression);
30970  var predicateFn;
30971
30972  if (comparator === true) {
30973    comparator = equals;
30974  } else if (!isFunction(comparator)) {
30975    comparator = function(actual, expected) {
30976      if (isUndefined(actual)) {
30977        // No substring matching against `undefined`
30978        return false;
30979      }
30980      if ((actual === null) || (expected === null)) {
30981        // No substring matching against `null`; only match against `null`
30982        return actual === expected;
30983      }
30984      if (isObject(expected) || (isObject(actual) && !hasCustomToString(actual))) {
30985        // Should not compare primitives against objects, unless they have custom `toString` method
30986        return false;
30987      }
30988
30989      actual = lowercase('' + actual);
30990      expected = lowercase('' + expected);
30991      return actual.indexOf(expected) !== -1;
30992    };
30993  }
30994
30995  predicateFn = function(item) {
30996    if (shouldMatchPrimitives && !isObject(item)) {
30997      return deepCompare(item, expression[anyPropertyKey], comparator, anyPropertyKey, false);
30998    }
30999    return deepCompare(item, expression, comparator, anyPropertyKey, matchAgainstAnyProp);
31000  };
31001
31002  return predicateFn;
31003}
31004
31005function deepCompare(actual, expected, comparator, anyPropertyKey, matchAgainstAnyProp, dontMatchWholeObject) {
31006  var actualType = getTypeForFilter(actual);
31007  var expectedType = getTypeForFilter(expected);
31008
31009  if ((expectedType === 'string') && (expected.charAt(0) === '!')) {
31010    return !deepCompare(actual, expected.substring(1), comparator, anyPropertyKey, matchAgainstAnyProp);
31011  } else if (isArray(actual)) {
31012    // In case `actual` is an array, consider it a match
31013    // if ANY of it's items matches `expected`
31014    return actual.some(function(item) {
31015      return deepCompare(item, expected, comparator, anyPropertyKey, matchAgainstAnyProp);
31016    });
31017  }
31018
31019  switch (actualType) {
31020    case 'object':
31021      var key;
31022      if (matchAgainstAnyProp) {
31023        for (key in actual) {
31024          // Under certain, rare, circumstances, key may not be a string and `charAt` will be undefined
31025          // See: https://github.com/angular/angular.js/issues/15644
31026          if (key.charAt && (key.charAt(0) !== '$') &&
31027              deepCompare(actual[key], expected, comparator, anyPropertyKey, true)) {
31028            return true;
31029          }
31030        }
31031        return dontMatchWholeObject ? false : deepCompare(actual, expected, comparator, anyPropertyKey, false);
31032      } else if (expectedType === 'object') {
31033        for (key in expected) {
31034          var expectedVal = expected[key];
31035          if (isFunction(expectedVal) || isUndefined(expectedVal)) {
31036            continue;
31037          }
31038
31039          var matchAnyProperty = key === anyPropertyKey;
31040          var actualVal = matchAnyProperty ? actual : actual[key];
31041          if (!deepCompare(actualVal, expectedVal, comparator, anyPropertyKey, matchAnyProperty, matchAnyProperty)) {
31042            return false;
31043          }
31044        }
31045        return true;
31046      } else {
31047        return comparator(actual, expected);
31048      }
31049    case 'function':
31050      return false;
31051    default:
31052      return comparator(actual, expected);
31053  }
31054}
31055
31056// Used for easily differentiating between `null` and actual `object`
31057function getTypeForFilter(val) {
31058  return (val === null) ? 'null' : typeof val;
31059}
31060
31061var MAX_DIGITS = 22;
31062var DECIMAL_SEP = '.';
31063var ZERO_CHAR = '0';
31064
31065/**
31066 * @ngdoc filter
31067 * @name currency
31068 * @kind function
31069 *
31070 * @description
31071 * Formats a number as a currency (ie $1,234.56). When no currency symbol is provided, default
31072 * symbol for current locale is used.
31073 *
31074 * @param {number} amount Input to filter.
31075 * @param {string=} symbol Currency symbol or identifier to be displayed.
31076 * @param {number=} fractionSize Number of decimal places to round the amount to, defaults to default max fraction size for current locale
31077 * @returns {string} Formatted number.
31078 *
31079 *
31080 * @example
31081   <example module="currencyExample" name="currency-filter">
31082     <file name="index.html">
31083       <script>
31084         angular.module('currencyExample', [])
31085           .controller('ExampleController', ['$scope', function($scope) {
31086             $scope.amount = 1234.56;
31087           }]);
31088       </script>
31089       <div ng-controller="ExampleController">
31090         <input type="number" ng-model="amount" aria-label="amount"> <br>
31091         default currency symbol ($): <span id="currency-default">{{amount | currency}}</span><br>
31092         custom currency identifier (USD$): <span id="currency-custom">{{amount | currency:"USD$"}}</span><br>
31093         no fractions (0): <span id="currency-no-fractions">{{amount | currency:"USD$":0}}</span>
31094       </div>
31095     </file>
31096     <file name="protractor.js" type="protractor">
31097       it('should init with 1234.56', function() {
31098         expect(element(by.id('currency-default')).getText()).toBe('$1,234.56');
31099         expect(element(by.id('currency-custom')).getText()).toBe('USD$1,234.56');
31100         expect(element(by.id('currency-no-fractions')).getText()).toBe('USD$1,235');
31101       });
31102       it('should update', function() {
31103         if (browser.params.browser === 'safari') {
31104           // Safari does not understand the minus key. See
31105           // https://github.com/angular/protractor/issues/481
31106           return;
31107         }
31108         element(by.model('amount')).clear();
31109         element(by.model('amount')).sendKeys('-1234');
31110         expect(element(by.id('currency-default')).getText()).toBe('-$1,234.00');
31111         expect(element(by.id('currency-custom')).getText()).toBe('-USD$1,234.00');
31112         expect(element(by.id('currency-no-fractions')).getText()).toBe('-USD$1,234');
31113       });
31114     </file>
31115   </example>
31116 */
31117currencyFilter.$inject = ['$locale'];
31118function currencyFilter($locale) {
31119  var formats = $locale.NUMBER_FORMATS;
31120  return function(amount, currencySymbol, fractionSize) {
31121    if (isUndefined(currencySymbol)) {
31122      currencySymbol = formats.CURRENCY_SYM;
31123    }
31124
31125    if (isUndefined(fractionSize)) {
31126      fractionSize = formats.PATTERNS[1].maxFrac;
31127    }
31128
31129    // 
31129if null or undefined pass it through
31130    return (amount == null)
31131        ? amount
31132        : formatNumber(amount, formats.PATTERNS[1], formats.GROUP_SEP, formats.DECIMAL_SEP, fractionSize).
31133            replace(/\u00A4/g
vendor: 13,487 bytes, lines 31133-31536
31133, currencySymbol);
31134  };
31135}
31136
31137/**
31138 * @ngdoc filter
31139 * @name number
31140 * @kind function
31141 *
31142 * @description
31143 * Formats a number as text.
31144 *
31145 * If the input is null or undefined, it will just be returned.
31146 * If the input is infinite (Infinity or -Infinity), the Infinity symbol '∞' or '-∞' is returned, respectively.
31147 * If the input is not a number an empty string is returned.
31148 *
31149 *
31150 * @param {number|string} number Number to format.
31151 * @param {(number|string)=} fractionSize Number of decimal places to round the number to.
31152 * If this is not provided then the fraction size is computed from the current locale's number
31153 * formatting pattern. In the case of the default locale, it will be 3.
31154 * @returns {string} Number rounded to `fractionSize` appropriately formatted based on the current
31155 *                   locale (e.g., in the en_US locale it will have "." as the decimal separator and
31156 *                   include "," group separators after each third digit).
31157 *
31158 * @example
31159   <example module="numberFilterExample" name="number-filter">
31160     <file name="index.html">
31161       <script>
31162         angular.module('numberFilterExample', [])
31163           .controller('ExampleController', ['$scope', function($scope) {
31164             $scope.val = 1234.56789;
31165           }]);
31166       </script>
31167       <div ng-controller="ExampleController">
31168         <label>Enter number: <input ng-model='val'></label><br>
31169         Default formatting: <span id='number-default'>{{val | number}}</span><br>
31170         No fractions: <span>{{val | number:0}}</span><br>
31171         Negative number: <span>{{-val | number:4}}</span>
31172       </div>
31173     </file>
31174     <file name="protractor.js" type="protractor">
31175       it('should format numbers', function() {
31176         expect(element(by.id('number-default')).getText()).toBe('1,234.568');
31177         expect(element(by.binding('val | number:0')).getText()).toBe('1,235');
31178         expect(element(by.binding('-val | number:4')).getText()).toBe('-1,234.5679');
31179       });
31180
31181       it('should update', function() {
31182         element(by.model('val')).clear();
31183         element(by.model('val')).sendKeys('3374.333');
31184         expect(element(by.id('number-default')).getText()).toBe('3,374.333');
31185         expect(element(by.binding('val | number:0')).getText()).toBe('3,374');
31186         expect(element(by.binding('-val | number:4')).getText()).toBe('-3,374.3330');
31187      });
31188     </file>
31189   </example>
31190 */
31191numberFilter.$inject = ['$locale'];
31192function numberFilter($locale) {
31193  var formats = $locale.NUMBER_FORMATS;
31194  return function(number, fractionSize) {
31195
31196    // if null or undefined pass it through
31197    return (number == null)
31198        ? number
31199        : formatNumber(number, formats.PATTERNS[0], formats.GROUP_SEP, formats.DECIMAL_SEP,
31200                       fractionSize);
31201  };
31202}
31203
31204/**
31205 * Parse a number (as a string) into three components that can be used
31206 * for formatting the number.
31207 *
31208 * (Significant bits of this parse algorithm came from https://github.com/MikeMcl/big.js/)
31209 *
31210 * @param  {string} numStr The number to parse
31211 * @return {object} An object describing this number, containing the following keys:
31212 *  - d : an array of digits containing leading zeros as necessary
31213 *  - i : the number of the digits in `d` that are to the left of the decimal point
31214 *  - e : the exponent for numbers that would need more than `MAX_DIGITS` digits in `d`
31215 *
31216 */
31217function parse(numStr) {
31218  var exponent = 0, digits, numberOfIntegerDigits;
31219  var i, j, zeros;
31220
31221  // Decimal point?
31222  if ((numberOfIntegerDigits = numStr.indexOf(DECIMAL_SEP)) > -1) {
31223    numStr = numStr.replace(DECIMAL_SEP, '');
31224  }
31225
31226  // Exponential form?
31227  if ((i = numStr.search(/e/i)) > 0) {
31228    // Work out the exponent.
31229    if (numberOfIntegerDigits < 0) numberOfIntegerDigits = i;
31230    numberOfIntegerDigits += +numStr.slice(i + 1);
31231    numStr = numStr.substring(0, i);
31232  } else if (numberOfIntegerDigits < 0) {
31233    // There was no decimal point or exponent so it is an integer.
31234    numberOfIntegerDigits = numStr.length;
31235  }
31236
31237  // Count the number of leading zeros.
31238  for (i = 0; numStr.charAt(i) === ZERO_CHAR; i++) { /* empty */ }
31239
31240  if (i === (zeros = numStr.length)) {
31241    // The digits are all zero.
31242    digits = [0];
31243    numberOfIntegerDigits = 1;
31244  } else {
31245    // Count the number of trailing zeros
31246    zeros--;
31247    while (numStr.charAt(zeros) === ZERO_CHAR) zeros--;
31248
31249    // Trailing zeros are insignificant so ignore them
31250    numberOfIntegerDigits -= i;
31251    digits = [];
31252    // Convert string to array of digits without leading/trailing zeros.
31253    for (j = 0; i <= zeros; i++, j++) {
31254      digits[j] = +numStr.charAt(i);
31255    }
31256  }
31257
31258  // If the number overflows the maximum allowed digits then use an exponent.
31259  if (numberOfIntegerDigits > MAX_DIGITS) {
31260    digits = digits.splice(0, MAX_DIGITS - 1);
31261    exponent = numberOfIntegerDigits - 1;
31262    numberOfIntegerDigits = 1;
31263  }
31264
31265  return { d: digits, e: exponent, i: numberOfIntegerDigits };
31266}
31267
31268/**
31269 * Round the parsed number to the specified number of decimal places
31270 * This function changed the parsedNumber in-place
31271 */
31272function roundNumber(parsedNumber, fractionSize, minFrac, maxFrac) {
31273    var digits = parsedNumber.d;
31274    var fractionLen = digits.length - parsedNumber.i;
31275
31276    // determine fractionSize if it is not specified; `+fractionSize` converts it to a number
31277    fractionSize = (isUndefined(fractionSize)) ? Math.min(Math.max(minFrac, fractionLen), maxFrac) : +fractionSize;
31278
31279    // The index of the digit to where rounding is to occur
31280    var roundAt = fractionSize + parsedNumber.i;
31281    var digit = digits[roundAt];
31282
31283    if (roundAt > 0) {
31284      // Drop fractional digits beyond `roundAt`
31285      digits.splice(Math.max(parsedNumber.i, roundAt));
31286
31287      // Set non-fractional digits beyond `roundAt` to 0
31288      for (var j = roundAt; j < digits.length; j++) {
31289        digits[j] = 0;
31290      }
31291    } else {
31292      // We rounded to zero so reset the parsedNumber
31293      fractionLen = Math.max(0, fractionLen);
31294      parsedNumber.i = 1;
31295      digits.length = Math.max(1, roundAt = fractionSize + 1);
31296      digits[0] = 0;
31297      for (var i = 1; i < roundAt; i++) digits[i] = 0;
31298    }
31299
31300    if (digit >= 5) {
31301      if (roundAt - 1 < 0) {
31302        for (var k = 0; k > roundAt; k--) {
31303          digits.unshift(0);
31304          parsedNumber.i++;
31305        }
31306        digits.unshift(1);
31307        parsedNumber.i++;
31308      } else {
31309        digits[roundAt - 1]++;
31310      }
31311    }
31312
31313    // Pad out with zeros to get the required fraction length
31314    for (; fractionLen < Math.max(0, fractionSize); fractionLen++) digits.push(0);
31315
31316
31317    // Do any carrying, e.g. a digit was rounded up to 10
31318    var carry = digits.reduceRight(function(carry, d, i, digits) {
31319      d = d + carry;
31320      digits[i] = d % 10;
31321      return Math.floor(d / 10);
31322    }, 0);
31323    if (carry) {
31324      digits.unshift(carry);
31325      parsedNumber.i++;
31326    }
31327}
31328
31329/**
31330 * Format a number into a string
31331 * @param  {number} number       The number to format
31332 * @param  {{
31333 *           minFrac, // the minimum number of digits required in the fraction part of the number
31334 *           maxFrac, // the maximum number of digits required in the fraction part of the number
31335 *           gSize,   // number of digits in each group of separated digits
31336 *           lgSize,  // number of digits in the last group of digits before the decimal separator
31337 *           negPre,  // the string to go in front of a negative number (e.g. `-` or `(`))
31338 *           posPre,  // the string to go in front of a positive number
31339 *           negSuf,  // the string to go after a negative number (e.g. `)`)
31340 *           posSuf   // the string to go after a positive number
31341 *         }} pattern
31342 * @param  {string} groupSep     The string to separate groups of number (e.g. `,`)
31343 * @param  {string} decimalSep   The string to act as the decimal separator (e.g. `.`)
31344 * @param  {[type]} fractionSize The size of the fractional part of the number
31345 * @return {string}              The number formatted as a string
31346 */
31347function formatNumber(number, pattern, groupSep, decimalSep, fractionSize) {
31348
31349  if (!(isString(number) || isNumber(number)) || isNaN(number)) return '';
31350
31351  var isInfinity = !isFinite(number);
31352  var isZero = false;
31353  var numStr = Math.abs(number) + '',
31354      formattedText = '',
31355      parsedNumber;
31356
31357  if (isInfinity) {
31358    formattedText = '\u221e';
31359  } else {
31360    parsedNumber = parse(numStr);
31361
31362    roundNumber(parsedNumber, fractionSize, pattern.minFrac, pattern.maxFrac);
31363
31364    var digits = parsedNumber.d;
31365    var integerLen = parsedNumber.i;
31366    var exponent = parsedNumber.e;
31367    var decimals = [];
31368    isZero = digits.reduce(function(isZero, d) { return isZero && !d; }, true);
31369
31370    // pad zeros for small numbers
31371    while (integerLen < 0) {
31372      digits.unshift(0);
31373      integerLen++;
31374    }
31375
31376    // extract decimals digits
31377    if (integerLen > 0) {
31378      decimals = digits.splice(integerLen, digits.length);
31379    } else {
31380      decimals = digits;
31381      digits = [0];
31382    }
31383
31384    // format the integer digits with grouping separators
31385    var groups = [];
31386    if (digits.length >= pattern.lgSize) {
31387      groups.unshift(digits.splice(-pattern.lgSize, digits.length).join(''));
31388    }
31389    while (digits.length > pattern.gSize) {
31390      groups.unshift(digits.splice(-pattern.gSize, digits.length).join(''));
31391    }
31392    if (digits.length) {
31393      groups.unshift(digits.join(''));
31394    }
31395    formattedText = groups.join(groupSep);
31396
31397    // append the decimal digits
31398    if (decimals.length) {
31399      formattedText += decimalSep + decimals.join('');
31400    }
31401
31402    if (exponent) {
31403      formattedText += 'e+' + exponent;
31404    }
31405  }
31406  if (number < 0 && !isZero) {
31407    return pattern.negPre + formattedText + pattern.negSuf;
31408  } else {
31409    return pattern.posPre + formattedText + pattern.posSuf;
31410  }
31411}
31412
31413function padNumber(num, digits, trim, negWrap) {
31414  var neg = '';
31415  if (num < 0 || (negWrap && num <= 0)) {
31416    if (negWrap) {
31417      num = -num + 1;
31418    } else {
31419      num = -num;
31420      neg = '-';
31421    }
31422  }
31423  num = '' + num;
31424  while (num.length < digits) num = ZERO_CHAR + num;
31425  if (trim) {
31426    num = num.substr(num.length - digits);
31427  }
31428  return neg + num;
31429}
31430
31431
31432function dateGetter(name, size, offset, trim, negWrap) {
31433  offset = offset || 0;
31434  return function(date) {
31435    var value = date['get' + name]();
31436    if (offset > 0 || value > -offset) {
31437      value += offset;
31438    }
31439    if (value === 0 && offset === -12) value = 12;
31440    return padNumber(value, size, trim, negWrap);
31441  };
31442}
31443
31444function dateStrGetter(name, shortForm, standAlone) {
31445  return function(date, formats) {
31446    var value = date['get' + name]();
31447    var propPrefix = (standAlone ? 'STANDALONE' : '') + (shortForm ? 'SHORT' : '');
31448    var get = uppercase(propPrefix + name);
31449
31450    return formats[get][value];
31451  };
31452}
31453
31454function timeZoneGetter(date, formats, offset) {
31455  var zone = -1 * offset;
31456  var paddedZone = (zone >= 0) ? '+' : '';
31457
31458  paddedZone += padNumber(Math[zone > 0 ? 'floor' : 'ceil'](zone / 60), 2) +
31459                padNumber(Math.abs(zone % 60), 2);
31460
31461  return paddedZone;
31462}
31463
31464function getFirstThursdayOfYear(year) {
31465    // 0 = index of January
31466    var dayOfWeekOnFirst = (new Date(year, 0, 1)).getDay();
31467    // 4 = index of Thursday (+1 to account for 1st = 5)
31468    // 11 = index of *next* Thursday (+1 account for 1st = 12)
31469    return new Date(year, 0, ((dayOfWeekOnFirst <= 4) ? 5 : 12) - dayOfWeekOnFirst);
31470}
31471
31472function getThursdayThisWeek(datetime) {
31473    return new Date(datetime.getFullYear(), datetime.getMonth(),
31474      // 4 = index of Thursday
31475      datetime.getDate() + (4 - datetime.getDay()));
31476}
31477
31478function weekGetter(size) {
31479   return function(date) {
31480      var firstThurs = getFirstThursdayOfYear(date.getFullYear()),
31481         thisThurs = getThursdayThisWeek(date);
31482
31483      var diff = +thisThurs - +firstThurs,
31484         result = 1 + Math.round(diff / 6.048e8); // 6.048e8 ms per week
31485
31486      return padNumber(result, size);
31487   };
31488}
31489
31490function ampmGetter(date, formats) {
31491  return date.getHours() < 12 ? formats.AMPMS[0] : formats.AMPMS[1];
31492}
31493
31494function eraGetter(date, formats) {
31495  return date.getFullYear() <= 0 ? formats.ERAS[0] : formats.ERAS[1];
31496}
31497
31498function longEraGetter(date, formats) {
31499  return date.getFullYear() <= 0 ? formats.ERANAMES[0] : formats.ERANAMES[1];
31500}
31501
31502var DATE_FORMATS = {
31503  yyyy: dateGetter('FullYear', 4, 0, false, true),
31504    yy: dateGetter('FullYear', 2, 0, true, true),
31505     y: dateGetter('FullYear', 1, 0, false, true),
31506  MMMM: dateStrGetter('Month'),
31507   MMM: dateStrGetter('Month', true),
31508    MM: dateGetter('Month', 2, 1),
31509     M: dateGetter('Month', 1, 1),
31510  LLLL: dateStrGetter('Month', false, true),
31511    dd: dateGetter('Date', 2),
31512     d: dateGetter('Date', 1),
31513    HH: dateGetter('Hours', 2),
31514     H: dateGetter('Hours', 1),
31515    hh: dateGetter('Hours', 2, -12),
31516     h: dateGetter('Hours', 1, -12),
31517    mm: dateGetter('Minutes', 2),
31518     m: dateGetter('Minutes', 1),
31519    ss: dateGetter('Seconds', 2),
31520     s: dateGetter('Seconds', 1),
31521     // while ISO 8601 requires fractions to be prefixed with `.` or `,`
31522     // we can be just safely rely on using `sss` since we currently don't support single or two digit fractions
31523   sss: dateGetter('Milliseconds', 3),
31524  EEEE: dateStrGetter('Day'),
31525   EEE: dateStrGetter('Day', true),
31526     a: ampmGetter,
31527     Z: timeZoneGetter,
31528    ww: weekGetter(2),
31529     w: weekGetter(1),
31530     G: eraGetter,
31531     GG: eraGetter,
31532     GGG: eraGetter,
31533     GGGG: longEraGetter
31534};
31535
31536var DATE_FORMATS_SPLIT = /((?:[^yMLdHhmsaZEwG']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|L+|d+|H+|h+|m+|s+|a|Z|G+|w+))(
31536.*)/,
31537    NUMBER_STRING = /^-?\d+$/;
31538
31539/**
31540 * @ngdoc filter
31541 * @name date
31542 * @kind function
31543 *
31544 * @description
31545 *   Formats `date` to a string based on the requested `format`.
31546 *
31547 *   `format` string can be composed of the following elements:
31548 *
31549 *   * `'yyyy'`: 4 digit representation of year (e.g. AD 1 => 0001, AD 2010 => 2010)
31550 *   * `'yy'`: 2 digit representation of year, padded (00-99). (e.g. AD 2001 => 01, AD 2010 => 10)
31551 *   * `'y'`: 1 digit representation of year, e.g. (AD 1 => 1, AD 199 => 199)
31552 *   * `'MMMM'`: Month in year (January-December)
31553 *   * `'MMM'`: Month in year (Jan-Dec)
31554 *   * `'MM'`: Month in year, padded (01-12)
31555 *   * `'M'`: Month in year (1-12)
31556 *   * `'LLLL'`: Stand-alone month in year (January-December)
31557 *   * `'dd'`: Day in month, padded (01-31)
31558 *   * `'d'`: Day in month (1-31)
31559 *   * `'EEEE'`: Day in Week,(Sunday-Saturday)
31560 *   * `'EEE'`: Day in Week, (Sun-Sat)
31561 *   * `'HH'`: Hour in day, padded (00-23)
31562 *   * `'H'`: Hour in day (0-23)
31563 *   * `'hh'`: Hour in AM/PM, padded (01-12)
31564 *   * `'h'`: Hour in AM/PM, (1-12)
31565 *   * `'mm'`: Minute in hour, padded (00-59)
31566 *   * `'m'`: Minute in hour (0-59)
31567 *   * `'ss'`: Second in minute, padded (00-59)
31568 *   * `'s'`: Second in minute (0-59)
31569 *   * `'sss'`: Millisecond in second, padded (000-999)
31570 *   * `'a'`: AM/PM marker
31571 *   * `'Z'`: 4 digit (+sign) representation of the timezone offset (-1200-+1200)
31572 *   * `'ww'`: Week of year, padded (00-53). Week 01 is the week with the first Thursday of the year
31573 *   * `'w'`: Week of year (0-53). Week 1 is the week with the first Thursday of the year
31574 *   * `'G'`, `'GG'`, `'GGG'`: The abbreviated form of the era string (e.g. 'AD')
31575 *   * `'GGGG'`: The long form of the era string (e.g. 'Anno Domini')
31576 *
31577 *   `format` string can also be one of the following predefined
31578 *   {@link guide/i18n localizable formats}:
31579 *
31580 *   * `'medium'`: equivalent to `'MMM d, y h:mm:ss a'` for en_US locale
31581 *     (e.g. Sep 3, 2010 12:05:08 PM)
31582 *   * `'short'`: equivalent to `'M/d/yy h:mm a'` for en_US  locale (e.g. 9/3/10 12:05 PM)
31583 *   * `'fullDate'`: equivalent to `'EEEE, MMMM d, y'` for en_US  locale
31584 *     (e.g. Friday, September 3, 2010)
31585 *   * `'longDate'`: equivalent to `'MMMM d, y'` for en_US  locale (e.g. September 3, 2010)
31586 *   * `'mediumDate'`: equivalent to `'MMM d, y'` for en_US  locale (e.g. Sep 3, 2010)
31587 *   * `'shortDate'`: equivalent to `'M/d/yy'` for en_US locale (e.g. 9/3/10)
31588 *   * `'mediumTime'`: equivalent to `'h:mm:ss a'` for en_US locale (e.g. 12:05:08 PM)
31589 *   * `'shortTime'`: equivalent to `'h:mm a'` for en_US locale (e.g. 12:05 PM)
31590 *
31591 *   `format` string can contain literal values. These need to be escaped by surrounding with single quotes (e.g.
31592 *   `"h 'in the morning'"`). In order to output a single quote, escape it - i.e., two single quotes in a sequence
31593 *   (e.g. `"h 'o''clock'"`)
vendor: 6,066 bytes, lines 31593-31757
31593.
31594 *
31595 * @param {(Date|number|string)} date Date to format either as Date object, milliseconds (string or
31596 *    number) or various ISO 8601 datetime string formats (e.g. yyyy-MM-ddTHH:mm:ss.sssZ and its
31597 *    shorter versions like yyyy-MM-ddTHH:mmZ, yyyy-MM-dd or yyyyMMddTHHmmssZ). If no timezone is
31598 *    specified in the string input, the time is considered to be in the local timezone.
31599 * @param {string=} format Formatting rules (see Description). If not specified,
31600 *    `mediumDate` is used.
31601 * @param {string=} timezone Timezone to be used for formatting. It understands UTC/GMT and the
31602 *    continental US time zone abbreviations, but for general use, use a time zone offset, for
31603 *    example, `'+0430'` (4 hours, 30 minutes east of the Greenwich meridian)
31604 *    If not specified, the timezone of the browser will be used.
31605 * @returns {string} Formatted string or the input if input is not recognized as date/millis.
31606 *
31607 * @example
31608   <example name="filter-date">
31609     <file name="index.html">
31610       <span ng-non-bindable>{{1288323623006 | date:'medium'}}</span>:
31611           <span>{{1288323623006 | date:'medium'}}</span><br>
31612       <span ng-non-bindable>{{1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'}}</span>:
31613          <span>{{1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'}}</span><br>
31614       <span ng-non-bindable>{{1288323623006 | date:'MM/dd/yyyy @ h:mma'}}</span>:
31615          <span>{{'1288323623006' | date:'MM/dd/yyyy @ h:mma'}}</span><br>
31616       <span ng-non-bindable>{{1288323623006 | date:"MM/dd/yyyy 'at' h:mma"}}</span>:
31617          <span>{{'1288323623006' | date:"MM/dd/yyyy 'at' h:mma"}}</span><br>
31618     </file>
31619     <file name="protractor.js" type="protractor">
31620       it('should format date', function() {
31621         expect(element(by.binding("1288323623006 | date:'medium'")).getText()).
31622            toMatch(/Oct 2\d, 2010 \d{1,2}:\d{2}:\d{2} (AM|PM)/);
31623         expect(element(by.binding("1288323623006 | date:'yyyy-MM-dd HH:mm:ss Z'")).getText()).
31624            toMatch(/2010-10-2\d \d{2}:\d{2}:\d{2} (-|\+)?\d{4}/);
31625         expect(element(by.binding("'1288323623006' | date:'MM/dd/yyyy @ h:mma'")).getText()).
31626            toMatch(/10\/2\d\/2010 @ \d{1,2}:\d{2}(AM|PM)/);
31627         expect(element(by.binding("'1288323623006' | date:\"MM/dd/yyyy 'at' h:mma\"")).getText()).
31628            toMatch(/10\/2\d\/2010 at \d{1,2}:\d{2}(AM|PM)/);
31629       });
31630     </file>
31631   </example>
31632 */
31633dateFilter.$inject = ['$locale'];
31634function dateFilter($locale) {
31635
31636
31637  var R_ISO8601_STR = /^(\d{4})-?(\d\d)-?(\d\d)(?:T(\d\d)(?::?(\d\d)(?::?(\d\d)(?:\.(\d+))?)?)?(Z|([+-])(\d\d):?(\d\d))?)?$/;
31638                     // 1        2       3         4          5          6          7          8  9     10      11
31639  function jsonStringToDate(string) {
31640    var match;
31641    if ((match = string.match(R_ISO8601_STR))) {
31642      var date = new Date(0),
31643          tzHour = 0,
31644          tzMin  = 0,
31645          dateSetter = match[8] ? date.setUTCFullYear : date.setFullYear,
31646          timeSetter = match[8] ? date.setUTCHours : date.setHours;
31647
31648      if (match[9]) {
31649        tzHour = toInt(match[9] + match[10]);
31650        tzMin = toInt(match[9] + match[11]);
31651      }
31652      dateSetter.call(date, toInt(match[1]), toInt(match[2]) - 1, toInt(match[3]));
31653      var h = toInt(match[4] || 0) - tzHour;
31654      var m = toInt(match[5] || 0) - tzMin;
31655      var s = toInt(match[6] || 0);
31656      var ms = Math.round(parseFloat('0.' + (match[7] || 0)) * 1000);
31657      timeSetter.call(date, h, m, s, ms);
31658      return date;
31659    }
31660    return string;
31661  }
31662
31663
31664  return function(date, format, timezone) {
31665    var text = '',
31666        parts = [],
31667        fn, match;
31668
31669    format = format || 'mediumDate';
31670    format = $locale.DATETIME_FORMATS[format] || format;
31671    if (isString(date)) {
31672      date = NUMBER_STRING.test(date) ? toInt(date) : jsonStringToDate(date);
31673    }
31674
31675    if (isNumber(date)) {
31676      date = new Date(date);
31677    }
31678
31679    if (!isDate(date) || !isFinite(date.getTime())) {
31680      return date;
31681    }
31682
31683    while (format) {
31684      match = DATE_FORMATS_SPLIT.exec(format);
31685      if (match) {
31686        parts = concat(parts, match, 1);
31687        format = parts.pop();
31688      } else {
31689        parts.push(format);
31690        format = null;
31691      }
31692    }
31693
31694    var dateTimezoneOffset = date.getTimezoneOffset();
31695    if (timezone) {
31696      dateTimezoneOffset = timezoneToOffset(timezone, dateTimezoneOffset);
31697      date = convertTimezoneToLocal(date, timezone, true);
31698    }
31699    forEach(parts, function(value) {
31700      fn = DATE_FORMATS[value];
31701      text += fn ? fn(date, $locale.DATETIME_FORMATS, dateTimezoneOffset)
31702                 : value === '\'\'' ? '\'' : value.replace(/(^'|'$)/g, '').replace(/''/g, '\'');
31703    });
31704
31705    return text;
31706  };
31707}
31708
31709
31710/**
31711 * @ngdoc filter
31712 * @name json
31713 * @kind function
31714 *
31715 * @description
31716 *   Allows you to convert a JavaScript object into JSON string.
31717 *
31718 *   This filter is mostly useful for debugging. When using the double curly {{value}} notation
31719 *   the binding is automatically converted to JSON.
31720 *
31721 * @param {*} object Any JavaScript object (including arrays and primitive types) to filter.
31722 * @param {number=} spacing The number of spaces to use per indentation, defaults to 2.
31723 * @returns {string} JSON string.
31724 *
31725 *
31726 * @example
31727   <example name="filter-json">
31728     <file name="index.html">
31729       <pre id="default-spacing">{{ {'name':'value'} | json }}</pre>
31730       <pre id="custom-spacing">{{ {'name':'value'} | json:4 }}</pre>
31731     </file>
31732     <file name="protractor.js" type="protractor">
31733       it('should jsonify filtered objects', function() {
31734         expect(element(by.id('default-spacing')).getText()).toMatch(/\{\n {2}"name": ?"value"\n}/);
31735         expect(element(by.id('custom-spacing')).getText()).toMatch(/\{\n {4}"name": ?"value"\n}/);
31736       });
31737     </file>
31738   </example>
31739 *
31740 */
31741function jsonFilter() {
31742  return function(object, spacing) {
31743    if (isUndefined(spacing)) {
31744        spacing = 2;
31745    }
31746    return toJson(object, spacing);
31747  };
31748}
31749
31750
31751/**
31752 * @ngdoc filter
31753 * @name lowercase
31754 * @kind function
31755 * @description
31756 * Converts string to lowercase.
31757 *
31757 @see angular.lowercase
31758 */
31759var lowercaseFilter = valueFn(lowercase);
31760
31761
31762/**
31763 * @ngdoc filter
31764 * @name uppercase
31765 * @kind function
31766 * @description
31767 * Converts string to uppercase.
31768 * @see angular.uppercase
vendor: 7,356 bytes, lines 31768-31944
31768
31769 */
31770var uppercaseFilter = valueFn(uppercase);
31771
31772/**
31773 * @ngdoc filter
31774 * @name limitTo
31775 * @kind function
31776 *
31777 * @description
31778 * Creates a new array or string containing only a specified number of elements. The elements are
31779 * taken from either the beginning or the end of the source array, string or number, as specified by
31780 * the value and sign (positive or negative) of `limit`. Other array-like objects are also supported
31781 * (e.g. array subclasses, NodeLists, jqLite/jQuery collections etc). If a number is used as input,
31782 * it is converted to a string.
31783 *
31784 * @param {Array|ArrayLike|string|number} input - Array/array-like, string or number to be limited.
31785 * @param {string|number} limit - The length of the returned array or string. If the `limit` number
31786 *     is positive, `limit` number of items from the beginning of the source array/string are copied.
31787 *     If the number is negative, `limit` number  of items from the end of the source array/string
31788 *     are copied. The `limit` will be trimmed if it exceeds `array.length`. If `limit` is undefined,
31789 *     the input will be returned unchanged.
31790 * @param {(string|number)=} begin - Index at which to begin limitation. As a negative index,
31791 *     `begin` indicates an offset from the end of `input`. Defaults to `0`.
31792 * @returns {Array|string} A new sub-array or substring of length `limit` or less if the input had
31793 *     less than `limit` elements.
31794 *
31795 * @example
31796   <example module="limitToExample" name="limit-to-filter">
31797     <file name="index.html">
31798       <script>
31799         angular.module('limitToExample', [])
31800           .controller('ExampleController', ['$scope', function($scope) {
31801             $scope.numbers = [1,2,3,4,5,6,7,8,9];
31802             $scope.letters = "abcdefghi";
31803             $scope.longNumber = 2345432342;
31804             $scope.numLimit = 3;
31805             $scope.letterLimit = 3;
31806             $scope.longNumberLimit = 3;
31807           }]);
31808       </script>
31809       <div ng-controller="ExampleController">
31810         <label>
31811            Limit {{numbers}} to:
31812            <input type="number" step="1" ng-model="numLimit">
31813         </label>
31814         <p>Output numbers: {{ numbers | limitTo:numLimit }}</p>
31815         <label>
31816            Limit {{letters}} to:
31817            <input type="number" step="1" ng-model="letterLimit">
31818         </label>
31819         <p>Output letters: {{ letters | limitTo:letterLimit }}</p>
31820         <label>
31821            Limit {{longNumber}} to:
31822            <input type="number" step="1" ng-model="longNumberLimit">
31823         </label>
31824         <p>Output long number: {{ longNumber | limitTo:longNumberLimit }}</p>
31825       </div>
31826     </file>
31827     <file name="protractor.js" type="protractor">
31828       var numLimitInput = element(by.model('numLimit'));
31829       var letterLimitInput = element(by.model('letterLimit'));
31830       var longNumberLimitInput = element(by.model('longNumberLimit'));
31831       var limitedNumbers = element(by.binding('numbers | limitTo:numLimit'));
31832       var limitedLetters = element(by.binding('letters | limitTo:letterLimit'));
31833       var limitedLongNumber = element(by.binding('longNumber | limitTo:longNumberLimit'));
31834
31835       it('should limit the number array to first three items', function() {
31836         expect(numLimitInput.getAttribute('value')).toBe('3');
31837         expect(letterLimitInput.getAttribute('value')).toBe('3');
31838         expect(longNumberLimitInput.getAttribute('value')).toBe('3');
31839         expect(limitedNumbers.getText()).toEqual('Output numbers: [1,2,3]');
31840         expect(limitedLetters.getText()).toEqual('Output letters: abc');
31841         expect(limitedLongNumber.getText()).toEqual('Output long number: 234');
31842       });
31843
31844       // There is a bug in safari and protractor that doesn't like the minus key
31845       // it('should update the output when -3 is entered', function() {
31846       //   numLimitInput.clear();
31847       //   numLimitInput.sendKeys('-3');
31848       //   letterLimitInput.clear();
31849       //   letterLimitInput.sendKeys('-3');
31850       //   longNumberLimitInput.clear();
31851       //   longNumberLimitInput.sendKeys('-3');
31852       //   expect(limitedNumbers.getText()).toEqual('Output numbers: [7,8,9]');
31853       //   expect(limitedLetters.getText()).toEqual('Output letters: ghi');
31854       //   expect(limitedLongNumber.getText()).toEqual('Output long number: 342');
31855       // });
31856
31857       it('should not exceed the maximum size of input array', function() {
31858         numLimitInput.clear();
31859         numLimitInput.sendKeys('100');
31860         letterLimitInput.clear();
31861         letterLimitInput.sendKeys('100');
31862         longNumberLimitInput.clear();
31863         longNumberLimitInput.sendKeys('100');
31864         expect(limitedNumbers.getText()).toEqual('Output numbers: [1,2,3,4,5,6,7,8,9]');
31865         expect(limitedLetters.getText()).toEqual('Output letters: abcdefghi');
31866         expect(limitedLongNumber.getText()).toEqual('Output long number: 2345432342');
31867       });
31868     </file>
31869   </example>
31870*/
31871function limitToFilter() {
31872  return function(input, limit, begin) {
31873    if (Math.abs(Number(limit)) === Infinity) {
31874      limit = Number(limit);
31875    } else {
31876      limit = toInt(limit);
31877    }
31878    if (isNumberNaN(limit)) return input;
31879
31880    if (isNumber(input)) input = input.toString();
31881    if (!isArrayLike(input)) return input;
31882
31883    begin = (!begin || isNaN(begin)) ? 0 : toInt(begin);
31884    begin = (begin < 0) ? Math.max(0, input.length + begin) : begin;
31885
31886    if (limit >= 0) {
31887      return sliceFn(input, begin, begin + limit);
31888    } else {
31889      if (begin === 0) {
31890        return sliceFn(input, limit, input.length);
31891      } else {
31892        return sliceFn(input, Math.max(0, begin + limit), begin);
31893      }
31894    }
31895  };
31896}
31897
31898function sliceFn(input, begin, end) {
31899  if (isString(input)) return input.slice(begin, end);
31900
31901  return slice.call(input, begin, end);
31902}
31903
31904/**
31905 * @ngdoc filter
31906 * @name orderBy
31907 * @kind function
31908 *
31909 * @description
31910 * Returns an array containing the items from the specified `collection`, ordered by a `comparator`
31911 * function based on the values computed using the `expression` predicate.
31912 *
31913 * For example, `[{id: 'foo'}, {id: 'bar'}] | orderBy:'id'` would result in
31914 * `[{id: 'bar'}, {id: 'foo'}]`.
31915 *
31916 * The `collection` can be an Array or array-like object (e.g. NodeList, jQuery object, TypedArray,
31917 * String, etc).
31918 *
31919 * The `expression` can be a single predicate, or a list of predicates each serving as a tie-breaker
31920 * for the preceding one. The `expression` is evaluated against each item and the output is used
31921 * for comparing with other items.
31922 *
31923 * You can change the sorting order by setting `reverse` to `true`. By default, items are sorted in
31924 * ascending order.
31925 *
31926 * The comparison is done using the `comparator` function. If none is specified, a default, built-in
31927 * comparator is used (see below for details - in a nutshell, it compares numbers numerically and
31928 * strings alphabetically).
31929 *
31930 * ### Under the hood
31931 *
31932 * Ordering the specified `collection` happens in two phases:
31933 *
31934 * 1. All items are passed through the predicate (or predicates), and the returned values are saved
31935 *    along with their type (`string`, `number` etc). For example, an item `{label: 'foo'}`, passed
31936 *    through a predicate that extracts the value of the `label` property, would be transformed to:
31937 *    ```
31938 *    {
31939 *      value: 'foo',
31940 *      type: 'string',
31941 *      index: ...
31942 *    }
31943 *    ```
31944 * 
319442. The comparator function is used to sort the items, based on the derived values, types and
31945 *    indices.
31946 *
31947 * If you use a custom comparator, it will be called with pairs of objects of the form
31948 * `{value: ..., type: '...', index: ...}` and is expected to return `0` if the objects are equal
31949 * (as far as the comparator is concerned), `-1` if the 1st one should be ranked higher than the
31950 * second, or `1` otherwise.
31951 *
31952 * In order to ensure that the sorting will be deterministic across platforms, if none of the
31953 * specified predicates can distinguish between two items, `orderBy` will automatically introduce a
31954 * dummy predicate that returns the item's index as `value`.
31955 * (If you are using a custom comparator, make sure it can handle this predicate as well.)
31956 *
31957 * Finally, in an attempt to simplify things, if a predicate returns an object as the extracted
31958 * value for an item, `orderBy` will try to convert that object to a primitive value, before passing
31959 * it to the comparator. The following rules govern the conversion:
31960 *
31961 * 1. If the object has a `valueOf()` method that returns a primitive, its return value will be
31962 *    used instead.<br />
31963 *    (If the object has a `valueOf()` method that returns another object, then the returned object
31964 *    will be used in subsequent steps.)
31965 * 2. If the object has a custom `toString()` method (i.e. not the one inherited from `Object`) that
31966 *    returns a primitive, its return value will be used instead.<br />
31967 *    (If the object has a `toString()` method that returns another object, then the returned object
31968 *    will be used in subsequent steps.)
31969 * 3. No conversion; the object itself is used.
31970 *
31971 * ### The default comparator
31972 *
31973 * The default, built-in comparator should be sufficient for most usecases. In short, it compares
31974 * numbers numerically, strings alphabetically (and case-insensitively), for objects falls back to
31975 * using their index in the original collection, and sorts values of different types by type.
31976 *
31977 * More specifically, it follows these steps to determine the relative order of items:
31978 *
31979 * 1. If the compared values are of different types, compare the types themselves alphabetically.
31980 * 2. If both values are of type `string`, compare them alphabetically in a case- and
31981 *    locale-insensitive way.
31982 * 3. If both values are objects, compare their indices instead.
31983 * 4. Otherwise, return:
31984 *    -  `0`, if the values are equal (by strict equality comparison, i.e. using `===`).
31985 *    - `-1`, if the 1st value is "less than" the 2nd value (compared using the `<` operator).
31986 *    -  `1`, otherwise.
31987 *
31988 * **Note:** If you notice numbers not being sorted as expected, make sure they are actually being
31989 *           saved as numbers and not strings.
31990 * **Note:** For the purpose of sorting, `null` values are treated as the string `'null'` (i.e.
31991 *           `type: 'string'`, `value: 'null'`). This may cause unexpected sort order relative to
31992 *           other values.
31993 *
31994 * @param {Array|ArrayLike} collection - The collection (array or array-like object) to sort.
31995 * @param {(Function|string|Array.<Function|string>)=} expression - A predicate (or list of
31996 *    predicates) to be used by the comparator to determine the order of elements.
31997 *
31998 *    Can be one of:
31999 *
32000 *    - `Function`: A getter function. This function will be called with each item as argument and
32001 *      the return value will be used for sorting.
32002 *    - `string`: An Angular
vendor: 19,123 bytes, lines 32002-32503
32002 expression. This expression will be evaluated against each item and the
32003 *      result will be used for sorting. For example, use `'label'` to sort by a property called
32004 *      `label` or `'label.substring(0, 3)'` to sort by the first 3 characters of the `label`
32005 *      property.<br />
32006 *      (The result of a constant expression is interpreted as a property name to be used for
32007 *      comparison. For example, use `'"special name"'` (note the extra pair of quotes) to sort by a
32008 *      property called `special name`.)<br />
32009 *      An expression can be optionally prefixed with `+` or `-` to control the sorting direction,
32010 *      ascending or descending. For example, `'+label'` or `'-label'`. If no property is provided,
32011 *      (e.g. `'+'` or `'-'`), the collection element itself is used in comparisons.
32012 *    - `Array`: An array of function and/or string predicates. If a predicate cannot determine the
32013 *      relative order of two items, the next predicate is used as a tie-breaker.
32014 *
32015 * **Note:** If the predicate is missing or empty then it defaults to `'+'`.
32016 *
32017 * @param {boolean=} reverse - If `true`, reverse the sorting order.
32018 * @param {(Function)=} comparator - The comparator function used to determine the relative order of
32019 *    value pairs. If omitted, the built-in comparator will be used.
32020 *
32021 * @returns {Array} - The sorted array.
32022 *
32023 *
32024 * @example
32025 * ### Ordering a table with `ngRepeat`
32026 *
32027 * The example below demonstrates a simple {@link ngRepeat ngRepeat}, where the data is sorted by
32028 * age in descending order (expression is set to `'-age'`). The `comparator` is not set, which means
32029 * it defaults to the built-in comparator.
32030 *
32031   <example name="orderBy-static" module="orderByExample1">
32032     <file name="index.html">
32033       <div ng-controller="ExampleController">
32034         <table class="friends">
32035           <tr>
32036             <th>Name</th>
32037             <th>Phone Number</th>
32038             <th>Age</th>
32039           </tr>
32040           <tr ng-repeat="friend in friends | orderBy:'-age'">
32041             <td>{{friend.name}}</td>
32042             <td>{{friend.phone}}</td>
32043             <td>{{friend.age}}</td>
32044           </tr>
32045         </table>
32046       </div>
32047     </file>
32048     <file name="script.js">
32049       angular.module('orderByExample1', [])
32050         .controller('ExampleController', ['$scope', function($scope) {
32051           $scope.friends = [
32052             {name: 'John',   phone: '555-1212',  age: 10},
32053             {name: 'Mary',   phone: '555-9876',  age: 19},
32054             {name: 'Mike',   phone: '555-4321',  age: 21},
32055             {name: 'Adam',   phone: '555-5678',  age: 35},
32056             {name: 'Julie',  phone: '555-8765',  age: 29}
32057           ];
32058         }]);
32059     </file>
32060     <file name="style.css">
32061       .friends {
32062         border-collapse: collapse;
32063       }
32064
32065       .friends th {
32066         border-bottom: 1px solid;
32067       }
32068       .friends td, .friends th {
32069         border-left: 1px solid;
32070         padding: 5px 10px;
32071       }
32072       .friends td:first-child, .friends th:first-child {
32073         border-left: none;
32074       }
32075     </file>
32076     <file name="protractor.js" type="protractor">
32077       // Element locators
32078       var names = element.all(by.repeater('friends').column('friend.name'));
32079
32080       it('should sort friends by age in reverse order', function() {
32081         expect(names.get(0).getText()).toBe('Adam');
32082         expect(names.get(1).getText()).toBe('Julie');
32083         expect(names.get(2).getText()).toBe('Mike');
32084         expect(names.get(3).getText()).toBe('Mary');
32085         expect(names.get(4).getText()).toBe('John');
32086       });
32087     </file>
32088   </example>
32089 * <hr />
32090 *
32091 * @example
32092 * ### Changing parameters dynamically
32093 *
32094 * All parameters can be changed dynamically. The next example shows how you can make the columns of
32095 * a table sortable, by binding the `expression` and `reverse` parameters to scope properties.
32096 *
32097   <example name="orderBy-dynamic" module="orderByExample2">
32098     <file name="index.html">
32099       <div ng-controller="ExampleController">
32100         <pre>Sort by = {{propertyName}}; reverse = {{reverse}}</pre>
32101         <hr/>
32102         <button ng-click="propertyName = null; reverse = false">Set to unsorted</button>
32103         <hr/>
32104         <table class="friends">
32105           <tr>
32106             <th>
32107               <button ng-click="sortBy('name')">Name</button>
32108               <span class="sortorder" ng-show="propertyName === 'name'" ng-class="{reverse: reverse}"></span>
32109             </th>
32110             <th>
32111               <button ng-click="sortBy('phone')">Phone Number</button>
32112               <span class="sortorder" ng-show="propertyName === 'phone'" ng-class="{reverse: reverse}"></span>
32113             </th>
32114             <th>
32115               <button ng-click="sortBy('age')">Age</button>
32116               <span class="sortorder" ng-show="propertyName === 'age'" ng-class="{reverse: reverse}"></span>
32117             </th>
32118           </tr>
32119           <tr ng-repeat="friend in friends | orderBy:propertyName:reverse">
32120             <td>{{friend.name}}</td>
32121             <td>{{friend.phone}}</td>
32122             <td>{{friend.age}}</td>
32123           </tr>
32124         </table>
32125       </div>
32126     </file>
32127     <file name="script.js">
32128       angular.module('orderByExample2', [])
32129         .controller('ExampleController', ['$scope', function($scope) {
32130           var friends = [
32131             {name: 'John',   phone: '555-1212',  age: 10},
32132             {name: 'Mary',   phone: '555-9876',  age: 19},
32133             {name: 'Mike',   phone: '555-4321',  age: 21},
32134             {name: 'Adam',   phone: '555-5678',  age: 35},
32135             {name: 'Julie',  phone: '555-8765',  age: 29}
32136           ];
32137
32138           $scope.propertyName = 'age';
32139           $scope.reverse = true;
32140           $scope.friends = friends;
32141
32142           $scope.sortBy = function(propertyName) {
32143             $scope.reverse = ($scope.propertyName === propertyName) ? !$scope.reverse : false;
32144             $scope.propertyName = propertyName;
32145           };
32146         }]);
32147     </file>
32148     <file name="style.css">
32149       .friends {
32150         border-collapse: collapse;
32151       }
32152
32153       .friends th {
32154         border-bottom: 1px solid;
32155       }
32156       .friends td, .friends th {
32157         border-left: 1px solid;
32158         padding: 5px 10px;
32159       }
32160       .friends td:first-child, .friends th:first-child {
32161         border-left: none;
32162       }
32163
32164       .sortorder:after {
32165         content: '\25b2';   // BLACK UP-POINTING TRIANGLE
32166       }
32167       .sortorder.reverse:after {
32168         content: '\25bc';   // BLACK DOWN-POINTING TRIANGLE
32169       }
32170     </file>
32171     <file name="protractor.js" type="protractor">
32172       // Element locators
32173       var unsortButton = element(by.partialButtonText('unsorted'));
32174       var nameHeader = element(by.partialButtonText('Name'));
32175       var phoneHeader = element(by.partialButtonText('Phone'));
32176       var ageHeader = element(by.partialButtonText('Age'));
32177       var firstName = element(by.repeater('friends').column('friend.name').row(0));
32178       var lastName = element(by.repeater('friends').column('friend.name').row(4));
32179
32180       it('should sort friends by some property, when clicking on the column header', function() {
32181         expect(firstName.getText()).toBe('Adam');
32182         expect(lastName.getText()).toBe('John');
32183
32184         phoneHeader.click();
32185         expect(firstName.getText()).toBe('John');
32186         expect(lastName.getText()).toBe('Mary');
32187
32188         nameHeader.click();
32189         expect(firstName.getText()).toBe('Adam');
32190         expect(lastName.getText()).toBe('Mike');
32191
32192         ageHeader.click();
32193         expect(firstName.getText()).toBe('John');
32194         expect(lastName.getText()).toBe('Adam');
32195       });
32196
32197       it('should sort friends in reverse order, when clicking on the same column', function() {
32198         expect(firstName.getText()).toBe('Adam');
32199         expect(lastName.getText()).toBe('John');
32200
32201         ageHeader.click();
32202         expect(firstName.getText()).toBe('John');
32203         expect(lastName.getText()).toBe('Adam');
32204
32205         ageHeader.click();
32206         expect(firstName.getText()).toBe('Adam');
32207         expect(lastName.getText()).toBe('John');
32208       });
32209
32210       it('should restore the original order, when clicking "Set to unsorted"', function() {
32211         expect(firstName.getText()).toBe('Adam');
32212         expect(lastName.getText()).toBe('John');
32213
32214         unsortButton.click();
32215         expect(firstName.getText()).toBe('John');
32216         expect(lastName.getText()).toBe('Julie');
32217       });
32218     </file>
32219   </example>
32220 * <hr />
32221 *
32222 * @example
32223 * ### Using `orderBy` inside a controller
32224 *
32225 * It is also possible to call the `orderBy` filter manually, by injecting `orderByFilter`, and
32226 * calling it with the desired parameters. (Alternatively, you could inject the `$filter` factory
32227 * and retrieve the `orderBy` filter with `$filter('orderBy')`.)
32228 *
32229   <example name="orderBy-call-manually" module="orderByExample3">
32230     <file name="index.html">
32231       <div ng-controller="ExampleController">
32232         <pre>Sort by = {{propertyName}}; reverse = {{reverse}}</pre>
32233         <hr/>
32234         <button ng-click="sortBy(null)">Set to unsorted</button>
32235         <hr/>
32236         <table class="friends">
32237           <tr>
32238             <th>
32239               <button ng-click="sortBy('name')">Name</button>
32240               <span class="sortorder" ng-show="propertyName === 'name'" ng-class="{reverse: reverse}"></span>
32241             </th>
32242             <th>
32243               <button ng-click="sortBy('phone')">Phone Number</button>
32244               <span class="sortorder" ng-show="propertyName === 'phone'" ng-class="{reverse: reverse}"></span>
32245             </th>
32246             <th>
32247               <button ng-click="sortBy('age')">Age</button>
32248               <span class="sortorder" ng-show="propertyName === 'age'" ng-class="{reverse: reverse}"></span>
32249             </th>
32250           </tr>
32251           <tr ng-repeat="friend in friends">
32252             <td>{{friend.name}}</td>
32253             <td>{{friend.phone}}</td>
32254             <td>{{friend.age}}</td>
32255           </tr>
32256         </table>
32257       </div>
32258     </file>
32259     <file name="script.js">
32260       angular.module('orderByExample3', [])
32261         .controller('ExampleController', ['$scope', 'orderByFilter', function($scope, orderBy) {
32262           var friends = [
32263             {name: 'John',   phone: '555-1212',  age: 10},
32264             {name: 'Mary',   phone: '555-9876',  age: 19},
32265             {name: 'Mike',   phone: '555-4321',  age: 21},
32266             {name: 'Adam',   phone: '555-5678',  age: 35},
32267             {name: 'Julie',  phone: '555-8765',  age: 29}
32268           ];
32269
32270           $scope.propertyName = 'age';
32271           $scope.reverse = true;
32272           $scope.friends = orderBy(friends, $scope.propertyName, $scope.reverse);
32273
32274           $scope.sortBy = function(propertyName) {
32275             $scope.reverse = (propertyName !== null && $scope.propertyName === propertyName)
32276                 ? !$scope.reverse : false;
32277             $scope.propertyName = propertyName;
32278             $scope.friends = orderBy(friends, $scope.propertyName, $scope.reverse);
32279           };
32280         }]);
32281     </file>
32282     <file name="style.css">
32283       .friends {
32284         border-collapse: collapse;
32285       }
32286
32287       .friends th {
32288         border-bottom: 1px solid;
32289       }
32290       .friends td, .friends th {
32291         border-left: 1px solid;
32292         padding: 5px 10px;
32293       }
32294       .friends td:first-child, .friends th:first-child {
32295         border-left: none;
32296       }
32297
32298       .sortorder:after {
32299         content: '\25b2';   // BLACK UP-POINTING TRIANGLE
32300       }
32301       .sortorder.reverse:after {
32302         content: '\25bc';   // BLACK DOWN-POINTING TRIANGLE
32303       }
32304     </file>
32305     <file name="protractor.js" type="protractor">
32306       // Element locators
32307       var unsortButton = element(by.partialButtonText('unsorted'));
32308       var nameHeader = element(by.partialButtonText('Name'));
32309       var phoneHeader = element(by.partialButtonText('Phone'));
32310       var ageHeader = element(by.partialButtonText('Age'));
32311       var firstName = element(by.repeater('friends').column('friend.name').row(0));
32312       var lastName = element(by.repeater('friends').column('friend.name').row(4));
32313
32314       it('should sort friends by some property, when clicking on the column header', function() {
32315         expect(firstName.getText()).toBe('Adam');
32316         expect(lastName.getText()).toBe('John');
32317
32318         phoneHeader.click();
32319         expect(firstName.getText()).toBe('John');
32320         expect(lastName.getText()).toBe('Mary');
32321
32322         nameHeader.click();
32323         expect(firstName.getText()).toBe('Adam');
32324         expect(lastName.getText()).toBe('Mike');
32325
32326         ageHeader.click();
32327         expect(firstName.getText()).toBe('John');
32328         expect(lastName.getText()).toBe('Adam');
32329       });
32330
32331       it('should sort friends in reverse order, when clicking on the same column', function() {
32332         expect(firstName.getText()).toBe('Adam');
32333         expect(lastName.getText()).toBe('John');
32334
32335         ageHeader.click();
32336         expect(firstName.getText()).toBe('John');
32337         expect(lastName.getText()).toBe('Adam');
32338
32339         ageHeader.click();
32340         expect(firstName.getText()).toBe('Adam');
32341         expect(lastName.getText()).toBe('John');
32342       });
32343
32344       it('should restore the original order, when clicking "Set to unsorted"', function() {
32345         expect(firstName.getText()).toBe('Adam');
32346         expect(lastName.getText()).toBe('John');
32347
32348         unsortButton.click();
32349         expect(firstName.getText()).toBe('John');
32350         expect(lastName.getText()).toBe('Julie');
32351       });
32352     </file>
32353   </example>
32354 * <hr />
32355 *
32356 * @example
32357 * ### Using a custom comparator
32358 *
32359 * If you have very specific requirements about the way items are sorted, you can pass your own
32360 * comparator function. For example, you might need to compare some strings in a locale-sensitive
32361 * way. (When specifying a custom comparator, you also need to pass a value for the `reverse`
32362 * argument - passing `false` retains the default sorting order, i.e. ascending.)
32363 *
32364   <example name="orderBy-custom-comparator" module="orderByExample4">
32365     <file name="index.html">
32366       <div ng-controller="ExampleController">
32367         <div class="friends-container custom-comparator">
32368           <h3>Locale-sensitive Comparator</h3>
32369           <table class="friends">
32370             <tr>
32371               <th>Name</th>
32372               <th>Favorite Letter</th>
32373             </tr>
32374             <tr ng-repeat="friend in friends | orderBy:'favoriteLetter':false:localeSensitiveComparator">
32375               <td>{{friend.name}}</td>
32376               <td>{{friend.favoriteLetter}}</td>
32377             </tr>
32378           </table>
32379         </div>
32380         <div class="friends-container default-comparator">
32381           <h3>Default Comparator</h3>
32382           <table class="friends">
32383             <tr>
32384               <th>Name</th>
32385               <th>Favorite Letter</th>
32386             </tr>
32387             <tr ng-repeat="friend in friends | orderBy:'favoriteLetter'">
32388               <td>{{friend.name}}</td>
32389               <td>{{friend.favoriteLetter}}</td>
32390             </tr>
32391           </table>
32392         </div>
32393       </div>
32394     </file>
32395     <file name="script.js">
32396       angular.module('orderByExample4', [])
32397         .controller('ExampleController', ['$scope', function($scope) {
32398           $scope.friends = [
32399             {name: 'John',   favoriteLetter: 'Ä'},
32400             {name: 'Mary',   favoriteLetter: 'Ü'},
32401             {name: 'Mike',   favoriteLetter: 'Ö'},
32402             {name: 'Adam',   favoriteLetter: 'H'},
32403             {name: 'Julie',  favoriteLetter: 'Z'}
32404           ];
32405
32406           $scope.localeSensitiveComparator = function(v1, v2) {
32407             // If we don't get strings, just compare by index
32408             if (v1.type !== 'string' || v2.type !== 'string') {
32409               return (v1.index < v2.index) ? -1 : 1;
32410             }
32411
32412             // Compare strings alphabetically, taking locale into account
32413             return v1.value.localeCompare(v2.value);
32414           };
32415         }]);
32416     </file>
32417     <file name="style.css">
32418       .friends-container {
32419         display: inline-block;
32420         margin: 0 30px;
32421       }
32422
32423       .friends {
32424         border-collapse: collapse;
32425       }
32426
32427       .friends th {
32428         border-bottom: 1px solid;
32429       }
32430       .friends td, .friends th {
32431         border-left: 1px solid;
32432         padding: 5px 10px;
32433       }
32434       .friends td:first-child, .friends th:first-child {
32435         border-left: none;
32436       }
32437     </file>
32438     <file name="protractor.js" type="protractor">
32439       // Element locators
32440       var container = element(by.css('.custom-comparator'));
32441       var names = container.all(by.repeater('friends').column('friend.name'));
32442
32443       it('should sort friends by favorite letter (in correct alphabetical order)', function() {
32444         expect(names.get(0).getText()).toBe('John');
32445         expect(names.get(1).getText()).toBe('Adam');
32446         expect(names.get(2).getText()).toBe('Mike');
32447         expect(names.get(3).getText()).toBe('Mary');
32448         expect(names.get(4).getText()).toBe('Julie');
32449       });
32450     </file>
32451   </example>
32452 *
32453 */
32454orderByFilter.$inject = ['$parse'];
32455function orderByFilter($parse) {
32456  return function(array, sortPredicate, reverseOrder, compareFn) {
32457
32458    if (array == null) return array;
32459    if (!isArrayLike(array)) {
32460      throw minErr('orderBy')('notarray', 'Expected array but received: {0}', array);
32461    }
32462
32463    if (!isArray(sortPredicate)) { sortPredicate = [sortPredicate]; }
32464    if (sortPredicate.length === 0) { sortPredicate = ['+']; }
32465
32466    var predicates = processPredicates(sortPredicate);
32467
32468    var descending = reverseOrder ? -1 : 1;
32469
32470    // Define the `compare()` function. Use a default comparator if none is specified.
32471    var compare = isFunction(compareFn) ? compareFn : defaultCompare;
32472
32473    // The next three lines are a version of a Swartzian Transform idiom from Perl
32474    // (sometimes called the Decorate-Sort-Undecorate idiom)
32475    // See https://en.wikipedia.org/wiki/Schwartzian_transform
32476    var compareValues = Array.prototype.map.call(array, getComparisonObject);
32477    compareValues.sort(doComparison);
32478    array = compareValues.map(function(item) { return item.value; });
32479
32480    return array;
32481
32482    function getComparisonObject(value, index) {
32483      // NOTE: We are adding an extra `tieBreaker` value based on the element's index.
32484      // This will be used to keep the sort stable when none of the input predicates can
32485      // distinguish between two elements.
32486      return {
32487        value: value,
32488        tieBreaker: {value: index, type: 'number', index: index},
32489        predicateValues: predicates.map(function(predicate) {
32490          return getPredicateValue(predicate.get(value), index);
32491        })
32492      };
32493    }
32494
32495    function doComparison(v1, v2) {
32496      for (var i = 0, ii = predicates.length; i < ii; i++) {
32497        var result = compare(v1.predicateValues[i], v2.predicateValues[i]);
32498        if (result) {
32499          return result * predicates[i].descending * descending;
32500        }
32501      }
32502
32503      return 
vendor: 5,453 bytes, lines 32503-32682
32503compare(v1.tieBreaker, v2.tieBreaker) * descending;
32504    }
32505  };
32506
32507  function processPredicates(sortPredicates) {
32508    return sortPredicates.map(function(predicate) {
32509      var descending = 1, get = identity;
32510
32511      if (isFunction(predicate)) {
32512        get = predicate;
32513      } else if (isString(predicate)) {
32514        if ((predicate.charAt(0) === '+' || predicate.charAt(0) === '-')) {
32515          descending = predicate.charAt(0) === '-' ? -1 : 1;
32516          predicate = predicate.substring(1);
32517        }
32518        if (predicate !== '') {
32519          get = $parse(predicate);
32520          if (get.constant) {
32521            var key = get();
32522            get = function(value) { return value[key]; };
32523          }
32524        }
32525      }
32526      return {get: get, descending: descending};
32527    });
32528  }
32529
32530  function isPrimitive(value) {
32531    switch (typeof value) {
32532      case 'number': /* falls through */
32533      case 'boolean': /* falls through */
32534      case 'string':
32535        return true;
32536      default:
32537        return false;
32538    }
32539  }
32540
32541  function objectValue(value) {
32542    // If `valueOf` is a valid function use that
32543    if (isFunction(value.valueOf)) {
32544      value = value.valueOf();
32545      if (isPrimitive(value)) return value;
32546    }
32547    // If `toString` is a valid function and not the one from `Object.prototype` use that
32548    if (hasCustomToString(value)) {
32549      value = value.toString();
32550      if (isPrimitive(value)) return value;
32551    }
32552
32553    return value;
32554  }
32555
32556  function getPredicateValue(value, index) {
32557    var type = typeof value;
32558    if (value === null) {
32559      type = 'string';
32560      value = 'null';
32561    } else if (type === 'object') {
32562      value = objectValue(value);
32563    }
32564    return {value: value, type: type, index: index};
32565  }
32566
32567  function defaultCompare(v1, v2) {
32568    var result = 0;
32569    var type1 = v1.type;
32570    var type2 = v2.type;
32571
32572    if (type1 === type2) {
32573      var value1 = v1.value;
32574      var value2 = v2.value;
32575
32576      if (type1 === 'string') {
32577        // Compare strings case-insensitively
32578        value1 = value1.toLowerCase();
32579        value2 = value2.toLowerCase();
32580      } else if (type1 === 'object') {
32581        // For basic objects, use the position of the object
32582        // in the collection instead of the value
32583        if (isObject(value1)) value1 = v1.index;
32584        if (isObject(value2)) value2 = v2.index;
32585      }
32586
32587      if (value1 !== value2) {
32588        result = value1 < value2 ? -1 : 1;
32589      }
32590    } else {
32591      result = type1 < type2 ? -1 : 1;
32592    }
32593
32594    return result;
32595  }
32596}
32597
32598function ngDirective(directive) {
32599  if (isFunction(directive)) {
32600    directive = {
32601      link: directive
32602    };
32603  }
32604  directive.restrict = directive.restrict || 'AC';
32605  return valueFn(directive);
32606}
32607
32608/**
32609 * @ngdoc directive
32610 * @name a
32611 * @restrict E
32612 *
32613 * @description
32614 * Modifies the default behavior of the html a tag so that the default action is prevented when
32615 * the href attribute is empty.
32616 *
32617 * For dynamically creating `href` attributes for a tags, see the {@link ng.ngHref `ngHref`} directive.
32618 */
32619var htmlAnchorDirective = valueFn({
32620  restrict: 'E',
32621  compile: function(element, attr) {
32622    if (!attr.href && !attr.xlinkHref) {
32623      return function(scope, element) {
32624        // If the linked element is not an anchor tag anymore, do nothing
32625        if (element[0].nodeName.toLowerCase() !== 'a') return;
32626
32627        // SVGAElement does not use the href attribute, but rather the 'xlinkHref' attribute.
32628        var href = toString.call(element.prop('href')) === '[object SVGAnimatedString]' ?
32629                   'xlink:href' : 'href';
32630        element.on('click', function(event) {
32631          // if we have no href url, then don't navigate anywhere.
32632          if (!element.attr(href)) {
32633            event.preventDefault();
32634          }
32635        });
32636      };
32637    }
32638  }
32639});
32640
32641/**
32642 * @ngdoc directive
32643 * @name ngHref
32644 * @restrict A
32645 * @priority 99
32646 *
32647 * @description
32648 * Using Angular markup like `{{hash}}` in an href attribute will
32649 * make the link go to the wrong URL if the user clicks it before
32650 * Angular has a chance to replace the `{{hash}}` markup with its
32651 * value. Until Angular replaces the markup the link will be broken
32652 * and will most likely return a 404 error. The `ngHref` directive
32653 * solves this problem.
32654 *
32655 * The wrong way to write it:
32656 * ```html
32657 * <a href="http://www.gravatar.com/avatar/{{hash}}">link1</a>
32658 * ```
32659 *
32660 * The correct way to write it:
32661 * ```html
32662 * <a ng-href="http://www.gravatar.com/avatar/{{hash}}">link1</a>
32663 * ```
32664 *
32665 * @element A
32666 * @param {template} ngHref any string which can contain `{{}}` markup.
32667 *
32668 * @example
32669 * This example shows various combinations of `href`, `ng-href` and `ng-click` attributes
32670 * in links and their different behaviors:
32671    <example name="ng-href">
32672      <file name="index.html">
32673        <input ng-model="value" /><br />
32674        <a id="link-1" href ng-click="value = 1">link 1</a> (link, don't reload)<br />
32675        <a id="link-2" href="" ng-click="value = 2">link 2</a> (link, don't reload)<br />
32676        <a id="link-3" ng-href="/{{'123'}}">link 3</a> (link, reload!)<br />
32677        <a id="link-4" href="" name="xx" ng-click="value = 4">anchor</a> (link, don't reload)<br />
32678        <a id="link-5" name="xxx" ng-click="value = 5">anchor</a> (no link)<br />
32679        <a id="link-6" ng-href="{{value}}">link</a> (link, change location)
32680      </file>
32681      <file name="protractor.js" type="protractor">
32682        it('should execute ng-click but not reload when href without value', function() {
32683          element(by.id('link-1')).click();
32684          expect(element(by.model('value')).getAttribute('value')).toEqual('1');
32685          expect(element(by.id('link-1')).getAttribute('href')).toBe('');
32686        });
32687
32688        it('should execute ng-click but not reload when href empty string', function() {
32689          element(by.id('link-2')).click();
32690          expect(element(by.model('value')).getAttribute('value')).toEqual('2');
32691          expect(element(by.id('link-2')).getAttribute('href')).toBe('');
32692        });
32693
32694        it('should execute ng-click and change url when ng-href specified', function() {
32695          expect(element(by.id('link-3')).getAttribute('href')).toMatch(/\/123$/);
32696
32697          element(by.id('link-3')).click();
32698
32699          // At this point, we navigate away from an Angular page, so we need
32700          // to use browser.driver to get the base webdriver.
32701
32702          browser.wait(function() {
32703            return browser.driver.getCurrentUrl().then(function(url) {
32704              return url.match(/\/123$/);
32705            });
32706          }, 5000, 'page should navigate to /123');
32707        });
32708
32709        it('should execute ng-click but not reload when href empty string and name specified', function() {
32710          element(by.id('link-4')).click();
32711          expect(element(by.model('value')).getAttribute('value')).toEqual('4');
32712          expect(element(by.id('link-4')).getAttribute('href')).toBe('');
32713        });
32714
32715        it('should execute ng-click but not reload when no href but name specified', function() {
32716          element(by.id('link-5')).click();
32717          expect(element(by.model('value')).getAttribute('value')).toEqual('5');
32718          expect(element(by.id('link-5')).getAttribute('href')).toBe(null);
32719        });
32720
32721        it('should only change url when only ng-href', function() {
32722          element(by.model('value')).clear();
32723          element(by.model('value')).sendKeys('6');
32724          expect(element(by.id('link-6')).getAttribute('href')).toMatch(/\/6$/);
32725
32726          element(by.id('link-6')).click();
32727
32728          // At this point, we navigate away from an Angular page, so we need
32729          // to use browser.driver to get the base webdriver.
32730          browser.wait(function() {
32731            return browser.driver.getCurrentUrl().then(function(url) {
32732              return url.match(/\/6$/);
32733            });
32734          }, 5000, 'page should navigate to /6');
32735        });
32736      </file>
32737    </example>
32738 */
32739
32740/**
32741 * @ngdoc directive
32742 * @name ngSrc
32743 * @restrict A
32744 * @priority 99
32745 *
32746 * @description
32747 * Using Angular markup like `{{hash}}` in a `src` attribute doesn't
32748 * work right: The browser will fetch from the URL with the literal
32749 * text `{{hash}}` until Angular replaces the expression inside
32750 * `{{hash}}`. The `ngSrc` directive solves this problem.
32751 *
32752 * The buggy way to write it:
32753 * ```html
32754 * <img src="http://www.gravatar.com/avatar/{{hash}}" alt="Description"/>
32755 * ```
32756 *
32757 * The correct way to write it:
32758 * ```html
32759 * <img ng-src="http://www.gravatar.com/avatar/{{hash}}" alt="Description" />
32760 * ```
32761 *
32762 * @element IMG
32763 * @param {template} ngSrc any string which can contain `{{}}` markup.
32764 */
32765
32766/**
32767 * @ngdoc directive
32768 * @name ngSrcset
32769 * @restrict A
32770 * @priority 99
32771 *
32772 * @description
32773 * Using Angular markup like `{{hash}}` in a `srcset` attribute doesn't
32774 * work right: The browser will fetch from the URL with the literal
32775 * text `{{hash}}` until Angular replaces the expression inside
32776 * `{{hash}}`. The `ngSrcset` directive solves this problem.
32777 *
32778 * The buggy way to write it:
32779 * ```html
32780 * <img srcset="http://www.gravatar.com/avatar/{{hash}} 2x" alt="Description"/>
32781 * ```
32782 *
32783 * The correct way to write it:
32784 * ```html
32785 * <img ng-srcset="http://www.gravatar.com/avatar/{{hash}} 2x" alt="Description" />
32786 * ```
32787 *
32788 * @element IMG
32789 * @param {template} ngSrcset any string which can contain `{{}}` markup.
32790 */
32791
32792/**
32793 * @ngdoc directive
32794 * @name ngDisabled
32795 * @restrict A
32796 * @priority 100
32797 *
32798 * @description
32799 *
32800 * This directive sets the `disabled` attribute on the element (typically a form control,
32801 * e.g. `input`, `button`, `select` etc.) if the
32802 * {@link guide/expression expression} inside `ngDisabled` evaluates to truthy.
32803 *
32804 * A special directive is necessary because we cannot use interpolation inside the `disabled`
32805 * attribute. See the {@link guide/interpolation interpolation guide} for more info.
32806 *
32807 * @example
32808    <example name="ng-disabled">
32809      <file name="index.html">
32810        <label>Click me to toggle: <input type="checkbox" ng-model="checked"></label><br/>
32811        <button ng-model="button" ng-disabled="checked">Button</button>
32812      </file>
32813      <file name="protractor.js" type="protractor">
32814        it('should toggle button', function() {
32815          expect(element(by.css('button')).getAttribute('disabled')).toBeFalsy();
32816          element(by.model('checked')).click();
32817          expect(element(by.css('button')).getAttribute('disabled')).toBeTruthy();
32818        });
32819      </file>
32820    </example>
32821 *
32822 * @element INPUT
32823 * @param {expression} ngDisabled If the {@link guide/expression expression} is truthy,
32824 *     then the `disabled` attribute will be set on the element
32825 */
32826
32827
32828/**
32829 * @ngdoc directive
32830 * @name ngChecked
32831 * @restrict A
32832 * @priority 100
32833 *
32834 * @description
32835 * Sets the `checked` attribute on the element, if the expression inside `ngChecked` is truthy.
32836 *
32837 * Note that this directive should not be used together with {@link ngModel `ngModel`},
32838 * as this can lead to unexpected behavior.
32839 *
32840 * A special directive is necessary because we cannot use interpolation inside the `checked`
32841 * attribute. See the {@link guide/interpolation interpolation guide} for more info.
32842 *
32843 * @example
32844    <example name="ng-checked">
32845      <file name="index.html">
32846        <label>Check me to check both: <input type="checkbox" ng-model="master"></label><br/>
32847        <input id="checkSlave" type="checkbox" ng-checked="master" aria-label="Slave input">
32848      </file>
32849      <file name="protractor.js" type="protractor">
32850        it('should check both checkBoxes', function() {
32851          expect(element(by.id('checkSlave')).getAttribute('checked')).toBeFalsy();
32852          element(by.model('master')).click();
32853          expect(element(by.id('checkSlave')).getAttribute('checked')).toBeTruthy();
32854        });
32855      </file>
32856    </example>
32857 *
32858 * @element INPUT
32859 * @param {expression} ngChecked If the {@link guide/expression expression} is truthy,
32860 *     then the `checked` attribute will be set on the element
32861 */
32862
32863
32864/**
32865 * @ngdoc directive
32866 * @name ngReadonly
32867 * @restrict A
32868 * @priority 100
32869 *
32870 * @description
32871 *
32872 * Sets the `readonly` attribute on the element, if the expression inside `ngReadonly` is truthy.
32873 * Note that `readonly` applies only to `input` elements with specific types. [See the input docs on
32874 * MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#attr-readonly) for more information.
32875 *
32876 * A special directive is necessary because we cannot use interpolation inside the `readonly`
32877 * attribute. See the {@link guide/interpolation interpolation guide} for more info.
32878 *
32879 * @example
32880    <example name="ng-readonly">
32881      <file name="index.html">
32882        <label>Check me to make text readonly: <input type="checkbox" ng-model="checked"></label><br/>
32883        <input type="text" ng-readonly="checked" value="I'm Angular" aria-label="Readonly field" />
32884      </file>
32885      <file name="protractor.js" type="protractor">
32886        it('should toggle readonly attr', function() {
32887          expect(element(by.css('[type="text"]')).getAttribute('readonly')).toBeFalsy();
32888          element(by.model('checked')).click();
32889          expect(element(by.css('[type="text"]')).getAttribute('readonly')).toBeTruthy();
32890        });
32891      </file>
32892    </example>
32893 *
32894 * @element INPUT
32895 * @param {expression} ngReadonly If the {@link guide/expression expression} is truthy,
32896 *     then special attribute "readonly" will be set on the element
32897 */
32898
32899
32900/**
32901 * @ngdoc directive
32902 * @name ngSelected
32903 * @restrict A
32904 * @priority 100
32905 *
32906 * @description
32907 *
32908 * Sets the `selected` attribute on the element, if the expression inside `ngSelected` is truthy.
32909 *
32910 * A special directive is necessary because we cannot use interpolation inside the `selected`
32911 * attribute. See the {@link guide/interpolation interpolation guide} for more info.
32912 *
32913 * <div class="alert alert-warning">
32914 *   **Note:** `ngSelected` does not interact with the `select` and `ngModel` directives, it only
32915 *   sets the `selected` attribute on the element. If you are using `ngModel` on the select, you
32916 *   should not use `ngSelected` on the options, as `ngModel` will set the select value and
32917 *   selected options.
32918 * </div>
32919 *
32920 * @example
32921    <example name="ng-selected">
32922      <file name="index.html">
32923        <label>Check me to select: <input type="checkbox" ng-model="selected"></label><br/>
32924        <select aria-label="ngSelected demo">
32925          <option>Hello!</option>
32926          <option id="greet" ng-selected="selected">Greetings!</option>
32927        </select>
32928      </file>
32929      <file name="protractor.js" type="protractor">
32930        it('should select Greetings!', function() {
32931          expect(element(by.id('greet')).getAttribute('selected')).toBeFalsy();
vendor: 8,388 bytes, lines 32932-33199
32932          element(by.model('selected')).click();
32933          expect(element(by.id('greet')).getAttribute('selected')).toBeTruthy();
32934        });
32935      </file>
32936    </example>
32937 *
32938 * @element OPTION
32939 * @param {expression} ngSelected If the {@link guide/expression expression} is truthy,
32940 *     then special attribute "selected" will be set on the element
32941 */
32942
32943/**
32944 * @ngdoc directive
32945 * @name ngOpen
32946 * @restrict A
32947 * @priority 100
32948 *
32949 * @description
32950 *
32951 * Sets the `open` attribute on the element, if the expression inside `ngOpen` is truthy.
32952 *
32953 * A special directive is necessary because we cannot use interpolation inside the `open`
32954 * attribute. See the {@link guide/interpolation interpolation guide} for more info.
32955 *
32956 * ## A note about browser compatibility
32957 *
32958 * Edge, Firefox, and Internet Explorer do not support the `details` element, it is
32959 * recommended to use {@link ng.ngShow} and {@link ng.ngHide} instead.
32960 *
32961 * @example
32962     <example name="ng-open">
32963       <file name="index.html">
32964         <label>Check me check multiple: <input type="checkbox" ng-model="open"></label><br/>
32965         <details id="details" ng-open="open">
32966            <summary>Show/Hide me</summary>
32967         </details>
32968       </file>
32969       <file name="protractor.js" type="protractor">
32970         it('should toggle open', function() {
32971           expect(element(by.id('details')).getAttribute('open')).toBeFalsy();
32972           element(by.model('open')).click();
32973           expect(element(by.id('details')).getAttribute('open')).toBeTruthy();
32974         });
32975       </file>
32976     </example>
32977 *
32978 * @element DETAILS
32979 * @param {expression} ngOpen If the {@link guide/expression expression} is truthy,
32980 *     then special attribute "open" will be set on the element
32981 */
32982
32983var ngAttributeAliasDirectives = {};
32984
32985// boolean attrs are evaluated
32986forEach(BOOLEAN_ATTR, function(propName, attrName) {
32987  // binding to multiple is not supported
32988  if (propName === 'multiple') return;
32989
32990  function defaultLinkFn(scope, element, attr) {
32991    scope.$watch(attr[normalized], function ngBooleanAttrWatchAction(value) {
32992      attr.$set(attrName, !!value);
32993    });
32994  }
32995
32996  var normalized = directiveNormalize('ng-' + attrName);
32997  var linkFn = defaultLinkFn;
32998
32999  if (propName === 'checked') {
33000    linkFn = function(scope, element, attr) {
33001      // ensuring ngChecked doesn't interfere with ngModel when both are set on the same input
33002      if (attr.ngModel !== attr[normalized]) {
33003        defaultLinkFn(scope, element, attr);
33004      }
33005    };
33006  }
33007
33008  ngAttributeAliasDirectives[normalized] = function() {
33009    return {
33010      restrict: 'A',
33011      priority: 100,
33012      link: linkFn
33013    };
33014  };
33015});
33016
33017// aliased input attrs are evaluated
33018forEach(ALIASED_ATTR, function(htmlAttr, ngAttr) {
33019  ngAttributeAliasDirectives[ngAttr] = function() {
33020    return {
33021      priority: 100,
33022      link: function(scope, element, attr) {
33023        //special case ngPattern when a literal regular expression value
33024        //is used as the expression (this way we don't have to watch anything).
33025        if (ngAttr === 'ngPattern' && attr.ngPattern.charAt(0) === '/') {
33026          var match = attr.ngPattern.match(REGEX_STRING_REGEXP);
33027          if (match) {
33028            attr.$set('ngPattern', new RegExp(match[1], match[2]));
33029            return;
33030          }
33031        }
33032
33033        scope.$watch(attr[ngAttr], function ngAttrAliasWatchAction(value) {
33034          attr.$set(ngAttr, value);
33035        });
33036      }
33037    };
33038  };
33039});
33040
33041// ng-src, ng-srcset, ng-href are interpolated
33042forEach(['src', 'srcset', 'href'], function(attrName) {
33043  var normalized = directiveNormalize('ng-' + attrName);
33044  ngAttributeAliasDirectives[normalized] = function() {
33045    return {
33046      priority: 99, // it needs to run after the attributes are interpolated
33047      link: function(scope, element, attr) {
33048        var propName = attrName,
33049            name = attrName;
33050
33051        if (attrName === 'href' &&
33052            toString.call(element.prop('href')) === '[object SVGAnimatedString]') {
33053          name = 'xlinkHref';
33054          attr.$attr[name] = 'xlink:href';
33055          propName = null;
33056        }
33057
33058        attr.$observe(normalized, function(value) {
33059          if (!value) {
33060            if (attrName === 'href') {
33061              attr.$set(name, null);
33062            }
33063            return;
33064          }
33065
33066          attr.$set(name, value);
33067
33068          // Support: IE 9-11 only
33069          // On IE, if "ng:src" directive declaration is used and "src" attribute doesn't exist
33070          // then calling element.setAttribute('src', 'foo') doesn't do anything, so we need
33071          // to set the property as well to achieve the desired effect.
33072          // We use attr[attrName] value since $set can sanitize the url.
33073          if (msie && propName) element.prop(propName, attr[name]);
33074        });
33075      }
33076    };
33077  };
33078});
33079
33080/* global -nullFormCtrl, -PENDING_CLASS, -SUBMITTED_CLASS
33081 */
33082var nullFormCtrl = {
33083  $addControl: noop,
33084  $$renameControl: nullFormRenameControl,
33085  $removeControl: noop,
33086  $setValidity: noop,
33087  $setDirty: noop,
33088  $setPristine: noop,
33089  $setSubmitted: noop
33090},
33091PENDING_CLASS = 'ng-pending',
33092SUBMITTED_CLASS = 'ng-submitted';
33093
33094function nullFormRenameControl(control, name) {
33095  control.$name = name;
33096}
33097
33098/**
33099 * @ngdoc type
33100 * @name form.FormController
33101 *
33102 * @property {boolean} $pristine True if user has not interacted with the form yet.
33103 * @property {boolean} $dirty True if user has already interacted with the form.
33104 * @property {boolean} $valid True if all of the containing forms and controls are valid.
33105 * @property {boolean} $invalid True if at least one containing control or form is invalid.
33106 * @property {boolean} $pending True if at least one containing control or form is pending.
33107 * @property {boolean} $submitted True if user has submitted the form even if its invalid.
33108 *
33109 * @property {Object} $error Is an object hash, containing references to controls or
33110 *  forms with failing validators, where:
33111 *
33112 *  - keys are validation tokens (error names),
33113 *  - values are arrays of controls or forms that have a failing validator for given error name.
33114 *
33115 *  Built-in validation tokens:
33116 *
33117 *  - `email`
33118 *  - `max`
33119 *  - `maxlength`
33120 *  - `min`
33121 *  - `minlength`
33122 *  - `number`
33123 *  - `pattern`
33124 *  - `required`
33125 *  - `url`
33126 *  - `date`
33127 *  - `datetimelocal`
33128 *  - `time`
33129 *  - `week`
33130 *  - `month`
33131 *
33132 * @description
33133 * `FormController` keeps track of all its controls and nested forms as well as the state of them,
33134 * such as being valid/invalid or dirty/pristine.
33135 *
33136 * Each {@link ng.directive:form form} directive creates an instance
33137 * of `FormController`.
33138 *
33139 */
33140//asks for $scope to fool the BC controller module
33141FormController.$inject = ['$element', '$attrs', '$scope', '$animate', '$interpolate'];
33142function FormController($element, $attrs, $scope, $animate, $interpolate) {
33143  this.$$controls = [];
33144
33145  // init state
33146  this.$error = {};
33147  this.$$success = {};
33148  this.$pending = undefined;
33149  this.$name = $interpolate($attrs.name || $attrs.ngForm || '')($scope);
33150  this.$dirty = false;
33151  this.$pristine = true;
33152  this.$valid = true;
33153  this.$invalid = false;
33154  this.$submitted = false;
33155  this.$$parentForm = nullFormCtrl;
33156
33157  this.$$element = $element;
33158  this.$$animate = $animate;
33159
33160  setupValidity(this);
33161}
33162
33163FormController.prototype = {
33164  /**
33165   * @ngdoc method
33166   * @name form.FormController#$rollbackViewValue
33167   *
33168   * @description
33169   * Rollback all form controls pending updates to the `$modelValue`.
33170   *
33171   * Updates may be pending by a debounced event or because the input is waiting for a some future
33172   * event defined in `ng-model-options`. This method is typically needed by the reset button of
33173   * a form that uses `ng-model-options` to pend updates.
33174   */
33175  $rollbackViewValue: function() {
33176    forEach(this.$$controls, function(control) {
33177      control.$rollbackViewValue();
33178    });
33179  },
33180
33181  /**
33182   * @ngdoc method
33183   * @name form.FormController#$commitViewValue
33184   *
33185   * @description
33186   * Commit all form controls pending updates to the `$modelValue`.
33187   *
33188   * Updates may be pending by a debounced event or because the input is waiting for a some future
33189   * event defined in `ng-model-options`. This method is rarely needed as `NgModelController`
33190   * usually handles calling this in response to input events.
33191   */
33192  $commitViewValue: function() {
33193    forEach(this.$$controls, function(control) {
33194      control.$commitViewValue();
33195    });
33196  },
33197
33198  /**
33199   * @ngdoc method
33200   * @name form.FormController#$addControl
33201   * @param {object} control control object, either a {@link form.FormController} or an
33202   * {@link ngModel.NgModelController}
33203   *
33204   * @description
33205   * Register a control with the form. Input elements using ngModelController do this automatically
33206   * when they are linked.
33207   *
33208   * Note that the current state of the control will not be reflected on the new parent form. This
33209   * is not an issue with normal use, as freshly compiled and linked controls are in a `$pristine`
33210   * state.
33211   *
33212   * However, if the method is used programmatically, for example by adding dynamically created controls,
33213   * or controls that have been previously removed without destroying their corresponding DOM element,
33214   * it's the developers responsibility to make sure the current state propagates to the parent form.
33215   *
33216   * For example, if an input control is added that is already `$dirty` and has `$error` properties,
33217   * calling `$setDirty()` and `$validate()` afterwards will propagate the state to the parent form.
33218   */
33219  $addControl: function(control) {
33220    // Breaking change - before, inputs whose name was "hasOwnProperty" were quietly ignored
33221    // and not added to the scope.  Now we throw an error.
33222    assertNotHasOwnProperty(control.$name, 'input');
33223    this.$$controls.push(control);
33224
33225    if (control.$name) {
33226      this[control.$name] = control;
33227    }
33228
33229    control.$$parentForm = this;
33230  },
33231
33232  // Private API: rename a form control
33233  $$renameControl: function(control, newName) {
33234    var oldName = control.$name;
33235
33236    if (this[oldName] === control) {
33237      delete this[oldName];
33238    }
33239    this[newName] = control;
33240    control.$name = newName;
33241  },
33242
33243  /**
33244   * @ngdoc method
33245   * @name form.FormController#$removeControl
33246   * @param {object} control control object, either a {@link form.FormController} or an
33247   * {@link ngModel.NgModelController}
33248   *
33249   * @description
33250   * Deregister a control from the form.
33251   *
33252   * Input elements using ngModelController do this automatically when they are destroyed.
33253   *
33254   * Note that only the removed control's validation state (`$errors`etc.) will be removed from the
33255   * form. `$dirty`, `$submitted` states will not be changed, because the expected behavior can be
33256   * different from case to case. For example, removing the only `$dirty` control from a form may or
33257   * may not mean that the form is still `$dirty`.
33258   */
33259  $removeControl: function(control) {
33260    if (control.$name && this[control.$name] === control) {
33261      delete this[control.$name];
33262    }
33263    forEach(this.$pending, function(value, name) {
33264      // eslint-disable-next-line no-invalid-this
33265      this.$setValidity(name, null, control);
33266    }, this);
33267    forEach(this.$error, function(value, name) {
33268      // eslint-disable-next-line no-invalid-this
33269      this.$setValidity(name, null, control);
33270    }, this);
33271    forEach(this.$$success, function(value, name) {
33272      // eslint-disable-next-line no-invalid-this
33273      this.$setValidity(name, null, control);
33274    }, this);
33275
33276    arrayRemove(this.$$controls, control);
33277    control.$$parentForm = nullFormCtrl;
33278  },
33279
33280  /**
33281   * @ngdoc method
33282   * @name form.FormController#$setDirty
33283   *
33284   * @description
33285   * Sets the form to a dirty state.
33286   *
33287   * This method can be called to add the 'ng-dirty' class and set the form to a dirty
33288   * state (ng-dirty class). This method will also propagate to parent forms.
33289   */
33290  $setDirty: function() {
33291    this.$$animate.removeClass(this.$$element, PRISTINE_CLASS);
33292    this.$$animate.addClass(this.$$element, DIRTY_CLASS);
33293    this.$dirty = true;
33294    this.$pristine = false;
33295    this.$$parentForm.$setDirty();
33296  },
33297
33298  /**
33299   * @ngdoc method
33300   * @name form.FormController#$setPristine
33301   *
33302   * @description
33303   * Sets the form to its pristine state.
33304   *
33305   * This method sets the form's `$pristine` state to true, the `$dirty` state to false, removes
33306   * the `ng-dirty` class and adds the `ng-pristine` class. Additionally, it sets the `$submitted`
33307   * state to false.
33308   *
33309   * This method will also propagate to all the controls contained in this form.
33310   *
33311   * Setting a form back to a pristine state is often useful when we want to 'reuse' a form after
33312   * saving or resetting it.
33313   */
33314  $setPristine: function() {
33315    this.$$animate.setClass(this.$$element, PRISTINE_CLASS, DIRTY_CLASS + ' ' + SUBMITTED_CLASS);
33316    this.$dirty = false;
vendor: 2,038 bytes, lines 33317-33400
33317    this.$pristine = true;
33318    this.$submitted = false;
33319    forEach(this.$$controls, function(control) {
33320      control.$setPristine();
33321    });
33322  },
33323
33324  /**
33325   * @ngdoc method
33326   * @name form.FormController#$setUntouched
33327   *
33328   * @description
33329   * Sets the form to its untouched state.
33330   *
33331   * This method can be called to remove the 'ng-touched' class and set the form controls to their
33332   * untouched state (ng-untouched class).
33333   *
33334   * Setting a form controls back to their untouched state is often useful when setting the form
33335   * back to its pristine state.
33336   */
33337  $setUntouched: function() {
33338    forEach(this.$$controls, function(control) {
33339      control.$setUntouched();
33340    });
33341  },
33342
33343  /**
33344   * @ngdoc method
33345   * @name form.FormController#$setSubmitted
33346   *
33347   * @description
33348   * Sets the form to its submitted state.
33349   */
33350  $setSubmitted: function() {
33351    this.$$animate.addClass(this.$$element, SUBMITTED_CLASS);
33352    this.$submitted = true;
33353    this.$$parentForm.$setSubmitted();
33354  }
33355};
33356
33357/**
33358 * @ngdoc method
33359 * @name form.FormController#$setValidity
33360 *
33361 * @description
33362 * Sets the validity of a form control.
33363 *
33364 * This method will also propagate to parent forms.
33365 */
33366addSetValidityMethod({
33367  clazz: FormController,
33368  set: function(object, property, controller) {
33369    var list = object[property];
33370    if (!list) {
33371      object[property] = [controller];
33372    } else {
33373      var index = list.indexOf(controller);
33374      if (index === -1) {
33375        list.push(controller);
33376      }
33377    }
33378  },
33379  unset: function(object, property, controller) {
33380    var list = object[property];
33381    if (!list) {
33382      return;
33383    }
33384    arrayRemove(list, controller);
33385    if (list.length === 0) {
33386      delete object[property];
33387    }
33388  }
33389});
33390
33391/**
33392 * @ngdoc directive
33393 * @name ngForm
33394 * @restrict EAC
33395 *
33396 * @description
33397 * Nestable alias of {@link ng.directive:form `form`} directive. HTML
33398 * does not allow nesting of form elements. It is useful to nest forms, for example if the validity of a
33399 * sub-group of controls needs to be determined.
33400 *
33401 * Note: the purpose of `ngForm` is to group controls,
33402 * but not to be a replacement for the `<form>` tag with all of its capabilities
33403 * (e.g. posting to the server, ...).
33404 *
33405 * @param {string=} ngForm|name Name of the form. If specified, the form controller will be published into
33406 *                       related scope, under this name.
33407 *
33408 */
33409
33410 /**
33411 * @ngdoc directive
33412 * @name form
33413 * @restrict E
33414 *
33415 * @description
33416 * Directive that instantiates
33417 * {@link form.FormController FormController}.
33418 *
33419 * If the `name` attribute is specified, the form controller is published onto the current scope under
33420 * this name.
33421 *
33422 * # Alias: {@link ng.directive:ngForm `ngForm`}
33423 *
33424 * In Angular, forms can be nested. This means that the outer form is valid when all of the child
33425 * forms are valid as well. However, browsers do not allow nesting of `<form>` elements, so
33426 * Angular provides the {@link ng.directive:ngForm `ngForm`} directive, which behaves identically to
33427 * `form` but can be nested. Nested forms can be useful, for example, if the validity of a sub-group
33428 * of controls needs to be determined.
33429 *
33430 * # CSS classes
33431 *  - `ng-valid` is set if the form is valid.
33432 *  - `ng-invalid` is set if the form is invalid.
33433 *  - `ng-pending` is set if the form is pending.
33434 *  - `ng-pristine` is set if the form is pristine.
33435 *  - `ng-dirty` is set if the form is dirty.
33436 *  - `ng-submitted` is set if the form was submitted.
33437 *
33438 * Keep in mind that ngAnimate can detect each of these classes when added and removed.
33439 *
33440 *
33441 * # Submitting a form and preventing the default action
33442 *
33443 * Since the role of forms in client-side Angular applications is different than in classical
33444 * roundtrip apps, it is desirable for the browser not to translate the form submission into a full
33445 * page reload that sends the data to the server. Instead some javascript logic should be triggered
33446 * to handle the form submission in an application-specific way.
33447 *
33448 * For this reason, Angular prevents the default action (form submission to the server) unless the
33449 * `<form>` element has an `action` attribute specified.
33450 *
33451 * You can use one of the following two ways to specify what javascript method should be called when
33452 * a form is submitted:
33453 *
33454 * - {@link ng.directive:ngSubmit ngSubmit} directive on the form element
33455 * - {@link ng.directive:ngClick ngClick} directive on the first
33456  *  button or input field of type submit (input[type=submit])
33457 *
33458 * To prevent double execution of the handler, use only one of the {@link ng.directive:ngSubmit ngSubmit}
33459 * or {@link ng.directive:ngClick ngClick} directives.
33460 * This is because of the following form submission rules in the HTML specification:
33461 *
33462 * - If a form has only one input field then hitting enter in this field triggers form submit
33463 * (`ngSubmit`)
33464 * - if a form has 2+ input fields and no buttons or input[type=submit] then hitting enter
33465 * doesn't trigger submit
33466 * - if a form has one or more input fields and one or more buttons or input[type=submit] then
33467 * hitting enter in any of the input fields will trigger the click handler on the *first* button or
33468 * input[type=submit] (`ngClick`) *and* a submit handler on the enclosing form (`ngSubmit`)
33469 *
33470 * Any pending `ngModelOptions` changes will take place immediately when an enclosing form is
33471 * submitted. Note that `ngClick` events will occur before the model is updated. Use `ngSubmit`
33472 * to have access to the updated model.
33473 *
33474 * ## Animation Hooks
33475 *
vendor: 11,664 bytes, lines 33475-33787
33475
33476 * Animations in ngForm are triggered when any of the associated CSS classes are added and removed.
33477 * These classes are: `.ng-pristine`, `.ng-dirty`, `.ng-invalid` and `.ng-valid` as well as any
33478 * other validations that are performed within the form. Animations in ngForm are similar to how
33479 * they work in ngClass and animations can be hooked into using CSS transitions, keyframes as well
33480 * as JS animations.
33481 *
33482 * The following example shows a simple way to utilize CSS transitions to style a form element
33483 * that has been rendered as invalid after it has been validated:
33484 *
33485 * <pre>
33486 * //be sure to include ngAnimate as a module to hook into more
33487 * //advanced animations
33488 * .my-form {
33489 *   transition:0.5s linear all;
33490 *   background: white;
33491 * }
33492 * .my-form.ng-invalid {
33493 *   background: red;
33494 *   color:white;
33495 * }
33496 * </pre>
33497 *
33498 * @example
33499    <example name="ng-form" deps="angular-animate.js" animations="true" fixBase="true" module="formExample">
33500      <file name="index.html">
33501       <script>
33502         angular.module('formExample', [])
33503           .controller('FormController', ['$scope', function($scope) {
33504             $scope.userType = 'guest';
33505           }]);
33506       </script>
33507       <style>
33508        .my-form {
33509          transition:all linear 0.5s;
33510          background: transparent;
33511        }
33512        .my-form.ng-invalid {
33513          background: red;
33514        }
33515       </style>
33516       <form name="myForm" ng-controller="FormController" class="my-form">
33517         userType: <input name="input" ng-model="userType" required>
33518         <span class="error" ng-show="myForm.input.$error.required">Required!</span><br>
33519         <code>userType = {{userType}}</code><br>
33520         <code>myForm.input.$valid = {{myForm.input.$valid}}</code><br>
33521         <code>myForm.input.$error = {{myForm.input.$error}}</code><br>
33522         <code>myForm.$valid = {{myForm.$valid}}</code><br>
33523         <code>myForm.$error.required = {{!!myForm.$error.required}}</code><br>
33524        </form>
33525      </file>
33526      <file name="protractor.js" type="protractor">
33527        it('should initialize to model', function() {
33528          var userType = element(by.binding('userType'));
33529          var valid = element(by.binding('myForm.input.$valid'));
33530
33531          expect(userType.getText()).toContain('guest');
33532          expect(valid.getText()).toContain('true');
33533        });
33534
33535        it('should be invalid if empty', function() {
33536          var userType = element(by.binding('userType'));
33537          var valid = element(by.binding('myForm.input.$valid'));
33538          var userInput = element(by.model('userType'));
33539
33540          userInput.clear();
33541          userInput.sendKeys('');
33542
33543          expect(userType.getText()).toEqual('userType =');
33544          expect(valid.getText()).toContain('false');
33545        });
33546      </file>
33547    </example>
33548 *
33549 * @param {string=} name Name of the form. If specified, the form controller will be published into
33550 *                       related scope, under this name.
33551 */
33552var formDirectiveFactory = function(isNgForm) {
33553  return ['$timeout', '$parse', function($timeout, $parse) {
33554    var formDirective = {
33555      name: 'form',
33556      restrict: isNgForm ? 'EAC' : 'E',
33557      require: ['form', '^^?form'], //first is the form's own ctrl, second is an optional parent form
33558      controller: FormController,
33559      compile: function ngFormCompile(formElement, attr) {
33560        // Setup initial state of the control
33561        formElement.addClass(PRISTINE_CLASS).addClass(VALID_CLASS);
33562
33563        var nameAttr = attr.name ? 'name' : (isNgForm && attr.ngForm ? 'ngForm' : false);
33564
33565        return {
33566          pre: function ngFormPreLink(scope, formElement, attr, ctrls) {
33567            var controller = ctrls[0];
33568
33569            // if `action` attr is not present on the form, prevent the default action (submission)
33570            if (!('action' in attr)) {
33571              // we can't use jq events because if a form is destroyed during submission the default
33572              // action is not prevented. see #1238
33573              //
33574              // IE 9 is not affected because it doesn't fire a submit event and try to do a full
33575              // page reload if the form was destroyed by submission of the form via a click handler
33576              // on a button in the form. Looks like an IE9 specific bug.
33577              var handleFormSubmission = function(event) {
33578                scope.$apply(function() {
33579                  controller.$commitViewValue();
33580                  controller.$setSubmitted();
33581                });
33582
33583                event.preventDefault();
33584              };
33585
33586              formElement[0].addEventListener('submit', handleFormSubmission);
33587
33588              // unregister the preventDefault listener so that we don't not leak memory but in a
33589              // way that will achieve the prevention of the default action.
33590              formElement.on('$destroy', function() {
33591                $timeout(function() {
33592                  formElement[0].removeEventListener('submit', handleFormSubmission);
33593                }, 0, false);
33594              });
33595            }
33596
33597            var parentFormCtrl = ctrls[1] || controller.$$parentForm;
33598            parentFormCtrl.$addControl(controller);
33599
33600            var setter = nameAttr ? getSetter(controller.$name) : noop;
33601
33602            if (nameAttr) {
33603              setter(scope, controller);
33604              attr.$observe(nameAttr, function(newValue) {
33605                if (controller.$name === newValue) return;
33606                setter(scope, undefined);
33607                controller.$$parentForm.$$renameControl(controller, newValue);
33608                setter = getSetter(controller.$name);
33609                setter(scope, controller);
33610              });
33611            }
33612            formElement.on('$destroy', function() {
33613              controller.$$parentForm.$removeControl(controller);
33614              setter(scope, undefined);
33615              extend(controller, nullFormCtrl); //stop propagating child destruction handlers upwards
33616            });
33617          }
33618        };
33619      }
33620    };
33621
33622    return formDirective;
33623
33624    function getSetter(expression) {
33625      if (expression === '') {
33626        //create an assignable expression, so forms with an empty name can be renamed later
33627        return $parse('this[""]').assign;
33628      }
33629      return $parse(expression).assign || noop;
33630    }
33631  }];
33632};
33633
33634var formDirective = formDirectiveFactory();
33635var ngFormDirective = formDirectiveFactory(true);
33636
33637
33638
33639// helper methods
33640function setupValidity(instance) {
33641  instance.$$classCache = {};
33642  instance.$$classCache[INVALID_CLASS] = !(instance.$$classCache[VALID_CLASS] = instance.$$element.hasClass(VALID_CLASS));
33643}
33644function addSetValidityMethod(context) {
33645  var clazz = context.clazz,
33646      set = context.set,
33647      unset = context.unset;
33648
33649  clazz.prototype.$setValidity = function(validationErrorKey, state, controller) {
33650    if (isUndefined(state)) {
33651      createAndSet(this, '$pending', validationErrorKey, controller);
33652    } else {
33653      unsetAndCleanup(this, '$pending', validationErrorKey, controller);
33654    }
33655    if (!isBoolean(state)) {
33656      unset(this.$error, validationErrorKey, controller);
33657      unset(this.$$success, validationErrorKey, controller);
33658    } else {
33659      if (state) {
33660        unset(this.$error, validationErrorKey, controller);
33661        set(this.$$success, validationErrorKey, controller);
33662      } else {
33663        set(this.$error, validationErrorKey, controller);
33664        unset(this.$$success, validationErrorKey, controller);
33665      }
33666    }
33667    if (this.$pending) {
33668      cachedToggleClass(this, PENDING_CLASS, true);
33669      this.$valid = this.$invalid = undefined;
33670      toggleValidationCss(this, '', null);
33671    } else {
33672      cachedToggleClass(this, PENDING_CLASS, false);
33673      this.$valid = isObjectEmpty(this.$error);
33674      this.$invalid = !this.$valid;
33675      toggleValidationCss(this, '', this.$valid);
33676    }
33677
33678    // re-read the state as the set/unset methods could have
33679    // combined state in this.$error[validationError] (used for forms),
33680    // where setting/unsetting only increments/decrements the value,
33681    // and does not replace it.
33682    var combinedState;
33683    if (this.$pending && this.$pending[validationErrorKey]) {
33684      combinedState = undefined;
33685    } else if (this.$error[validationErrorKey]) {
33686      combinedState = false;
33687    } else if (this.$$success[validationErrorKey]) {
33688      combinedState = true;
33689    } else {
33690      combinedState = null;
33691    }
33692
33693    toggleValidationCss(this, validationErrorKey, combinedState);
33694    this.$$parentForm.$setValidity(validationErrorKey, combinedState, this);
33695  };
33696
33697  function createAndSet(ctrl, name, value, controller) {
33698    if (!ctrl[name]) {
33699      ctrl[name] = {};
33700    }
33701    set(ctrl[name], value, controller);
33702  }
33703
33704  function unsetAndCleanup(ctrl, name, value, controller) {
33705    if (ctrl[name]) {
33706      unset(ctrl[name], value, controller);
33707    }
33708    if (isObjectEmpty(ctrl[name])) {
33709      ctrl[name] = undefined;
33710    }
33711  }
33712
33713  function cachedToggleClass(ctrl, className, switchValue) {
33714    if (switchValue && !ctrl.$$classCache[className]) {
33715      ctrl.$$animate.addClass(ctrl.$$element, className);
33716      ctrl.$$classCache[className] = true;
33717    } else if (!switchValue && ctrl.$$classCache[className]) {
33718      ctrl.$$animate.removeClass(ctrl.$$element, className);
33719      ctrl.$$classCache[className] = false;
33720    }
33721  }
33722
33723  function toggleValidationCss(ctrl, validationErrorKey, isValid) {
33724    validationErrorKey = validationErrorKey ? '-' + snake_case(validationErrorKey, '-') : '';
33725
33726    cachedToggleClass(ctrl, VALID_CLASS + validationErrorKey, isValid === true);
33727    cachedToggleClass(ctrl, INVALID_CLASS + validationErrorKey, isValid === false);
33728  }
33729}
33730
33731function isObjectEmpty(obj) {
33732  if (obj) {
33733    for (var prop in obj) {
33734      if (obj.hasOwnProperty(prop)) {
33735        return false;
33736      }
33737    }
33738  }
33739  return true;
33740}
33741
33742/* global
33743  VALID_CLASS: false,
33744  INVALID_CLASS: false,
33745  PRISTINE_CLASS: false,
33746  DIRTY_CLASS: false,
33747  ngModelMinErr: false
33748*/
33749
33750// Regex code was initially obtained from SO prior to modification: https://stackoverflow.com/questions/3143070/javascript-regex-iso-datetime#answer-3143231
33751var 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)$/;
33752// See valid URLs in RFC3987 (http://tools.ietf.org/html/rfc3987)
33753// Note: We are being more lenient, because browsers are too.
33754//   1. Scheme
33755//   2. Slashes
33756//   3. Username
33757//   4. Password
33758//   5. Hostname
33759//   6. Port
33760//   7. Path
33761//   8. Query
33762//   9. Fragment
33763//                 1111111111111111 222   333333    44444        55555555555555555555555     666     77777777     8888888     999
33764var URL_REGEXP = /^[a-z][a-z\d.+-]*:\/*(?:[^:@]+(?::[^@]+)?@)?(?:[^\s:/?#]+|\[[a-f\d:]+])(?::\d+)?(?:\/[^?#]*)?(?:\?[^#]*)?(?:#.*)?$/i;
33765// eslint-disable-next-line max-len
33766var EMAIL_REGEXP = /^(?=.{1,254}$)(?=.{1,64}@)[-!#$%&'*+/0-9=?A-Z^_`a-z{|}~]+(\.[-!#$%&'*+/0-9=?A-Z^_`a-z{|}~]+)*@[A-Za-z0-9]([A-Za-z0-9-]{0,61}[A-Za-z0-9])?(\.[A-Za-z0-9]([A-Za-z0-9-]{0,61}[A-Za-z0-9])?)*$/;
33767var NUMBER_REGEXP = /^\s*(-|\+)?(\d+|(\d*(\.\d*)))([eE][+-]?\d+)?\s*$/;
33768var DATE_REGEXP = /^(\d{4,})-(\d{2})-(\d{2})$/;
33769var DATETIMELOCAL_REGEXP = /^(\d{4,})-(\d\d)-(\d\d)T(\d\d):(\d\d)(?::(\d\d)(\.\d{1,3})?)?$/;
33770var WEEK_REGEXP = /^(\d{4,})-W(\d\d)$/;
33771var MONTH_REGEXP = /^(\d{4,})-(\d\d)$/;
33772var TIME_REGEXP = /^(\d\d):(\d\d)(?::(\d\d)(\.\d{1,3})?)?$/;
33773
33774var PARTIAL_VALIDATION_EVENTS = 'keydown wheel mousedown';
33775var PARTIAL_VALIDATION_TYPES = createMap();
33776forEach('date,datetime-local,month,time,week'.split(','), function(type) {
33777  PARTIAL_VALIDATION_TYPES[type] = true;
33778});
33779
33780var inputType = {
33781
33782  /**
33783   * @ngdoc input
33784   * @name input[text]
33785   *
33786   * @description
33787   * Standard HTML text input with 
33787angular data binding, inherited by most of the `input` elements.
33788   *
33789   *
33790   * @param {string} ngModel Assignable angular expression to data-bind to.
33791   * @param {string=} name Property name of the form under which the control is published.
33792   * @param {string=} required Adds `required` validation error key if the value is not entered.
33793   * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
33794   *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
33795   *    `required` when you want to data-bind to the `required` attribute.
33796   * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
33797   *    minlength.
33798   * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
33799   *    maxlength. Setting the attribute to a negative or non-numeric value, allows view values of
33800   *    any length.
33801   * @param {string=} pattern Similar to `ngPattern` except that the attribute value is the actual string
33802   *    that contains the regular expression body that will be converted to a regular expression
33803   *    as in the ngPattern directive.
33804   * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel {@link ngModel.NgModelController#$viewValue $viewValue}
33805   *    does not match a RegExp found by evaluating the Angular expression given in the attribute value.
33806   *    If the expression evaluates to a RegExp object, then this is used directly.
33807   *    If the expression evaluates to a string, then it will be converted to a RegExp
33808   *    after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to
33809   *    `new RegExp('^abc$')`.<br />
33810   *    **Note:** Avoid using the `g` flag on the RegExp, as it will cause each successive search to
33811   *    start at the index of the last search's match, thus not taking the whole input value into
33812   *    account.
33813   * @param {string=} ngChange Angular expression to be executed when input changes due to user
33814   *    interaction with the input element.
33815   * @param {boolean=} [ngTrim=true] If set to false Angular will not automatically trim the input.
33816   *    This parameter is ignored for input[type=password] controls, which will never trim the
33817   *    input.
33818   *
33819   * @example
33820      <example name="text-input-directive" module="textInputExample">
33821        <file name="index.html">
33822         <script>
33823           angular.module('textInputExample', [])
33824             .controller('ExampleController', ['$scope', function($scope) {
33825               $scope.example = {
33826                 text: 'guest',
33827                 word: /^\s*\w*\s*$/
33828               };
33829             }]);
33830         </script>
33831         <form name="myForm" ng-controller="ExampleController">
33832           <label>Single word:
33833             <input type="text" name="input" ng-model="example.text"
33834                    ng-pattern="example.word" required ng-trim="false">
33835           </label>
33836           <div role="alert">
33837             <span class="error" ng-show="myForm.input.$error.required">
33838               Required!</span>
33839             <span class="error" ng-show="myForm.input.$error.pattern">
33840               Single word only!</span>
33841           </div>
33842           <code>text = {{example.text}}</code><br/>
33843           <code>myForm.input.$valid = {{myForm.input.$valid}}</code><br/>
33844           <code>myForm.input.$error = {{myForm.input.$error}}</code><br/>
33845           <code>myForm.$valid = {{myForm.$valid}}</code><br/>
33846           <code>myForm.$error.required = {{!!myForm.$error.required}}</code><br/>
33847          </form>
33848        </file>
33849        <file name="protractor.js" type="protractor">
33850          var text = element(by.binding('example.text'));
33851          var valid = element(by.binding('myForm.input.$valid'));
33852          var input = element(by.model('example.text'));
33853
33854          it('should initialize to model', function() {
33855            expect(text.getText()).toContain('guest');
33856            expect(valid.getText()).toContain('true');
33857          });
33858
33859          it('should be invalid if empty', function() {
33860            input.clear();
33861            input.sendKeys('');
33862
33863            expect(text.getText()).toEqual('text =');
33864            expect(valid.getText()).toContain('false');
33865          });
33866
33867          it('should be invalid if multi word', function() {
33868            input.clear();
33869            input.sendKeys('hello world');
33870
33871            expect(valid.getText()).toContain('false');
33872          });
33873        </file>
33874      </example>
33875   */
33876  'text': textInputType,
33877
33878    /**
33879     * @ngdoc input
33880     * @name input[date]
33881     *
33882     * @description
33883     * Input with date validation and transformation. In browsers that do not yet support
33884     * the HTML5 date input, a text element will be used. In that case, text must be entered in a valid ISO-8601
33885     * date format (yyyy-MM-dd), for example: `2009-01-06`. Since many
33886     * modern browsers do not yet support this input type, it is important to provide cues to users on the
33887     * expected input format via a placeholder or label.
33888     *
33889     * The model must always be a Date object, otherwise Angular will throw an error.
33890     * Invalid `Date` objects (dates whose `getTime()` is `NaN`) will be rendered as an empty string.
33891     *
33892     * The timezone to be used to read/write the `Date` instance in the model can be defined using
33893     * {@link ng.directive:ngModelOptions ngModelOptions}. By default, this is the timezone of the browser.
33894     *
33895     * @param {string} ngModel Assignable angular expression to data-bind to.
33896     * @param {string=} name Property name of the form under which the control is published.
33897     * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`. This must be a
33898     *   valid ISO date string (yyyy-MM-dd). You can also use interpolation inside this attribute
33899     *   (e.g. `min="{{minDate | date:'yyyy-MM-dd'}}"`). Note that `min` will also add native HTML5
33900     *   constraint validation.
33901     * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`. This must be
33902     *   a valid ISO date string (yyyy-MM-dd). You can also use interpolation inside this attribute
33903     *   (e.g. `max="{{maxDate | date:'yyyy-MM-dd'}}"`). Note that `max` will also add native HTML5
33904     *   constraint validation.
33905     * @param {(date|string)=} ngMin Sets the `min` validation constraint to the Date / ISO date string
33906     *   the `ngMin` expression evaluates to. Note that it does not set the `min` attribute.
33907     * @param {(date|string)=} ngMax Sets the `max` validation constraint to the Date / ISO date string
33908     *   the `ngMax` expression evaluates to. Note that it does not set the `max` attribute.
33909     * @param {string=} required Sets `required` validation error key if the value is not entered.
33910     * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
33911     *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
33912     *    `required` when you want to data-bind to the `required` attribute.
33913     * @param {string=} ngChange Angular expression to be executed when input changes due to user
33914     *    interaction with the input element.
33915     *
33916     * @example
33917     <example name="date-input-directive" module="dateInputExample">
33918     <file name="index.html">
33919       <script>
33920          angular.module('dateInputExample', [])
33921            .controller('DateController', ['$scope', function($scope) {
33922              $scope.example = {
33923                value: new Date(2013, 9, 22)
33924              };
33925            }]);
33926       </script>
33927       <form name="myForm" ng-controller="DateController as dateCtrl">
33928          <label for="exampleInput">Pick a date in 2013:</label>
33929          <input type="date" id="exampleInput" name="input" ng-model="example.value"
33930              placeholder="yyyy-MM-dd" min="2013-01-01" max="2013-12-31" required />
33931          <div role="alert">
33932            <span class="error" ng-show="myForm.input.$error.required">
33933                Required!</span>
33934            <span class="error" ng-show="myForm.input.$error.date">
33935                Not a valid date!</span>
33936           </div>
33937           <tt>value = {{example.value | date: "yyyy-MM-dd"}}</tt><br/>
33938           <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
33939           <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
33940           <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
33941           <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
33942       </form>
33943     </file>
33944     <file name="protractor.js" type="protractor">
33945        var value = element(by.binding('example.value | date: "yyyy-MM-dd"'));
33946        var valid = element(by.binding('myForm.input.$valid'));
33947
33948        // currently protractor/webdriver does not support
33949        // sending keys to all known HTML5 input controls
33950        // for various browsers (see https://github.com/angular/protractor/issues/562).
33951        function setInput(val) {
33952          // set the value of the element and force validation.
33953          var scr = "var ipt = document.getElementById('exampleInput'); " +
33954          "ipt.value = '" + val + "';" +
33955          "angular.element(ipt).scope().$apply(function(s) { s.myForm[ipt.name].$setViewValue('" + val + "'); });";
33956          browser.executeScript(scr);
33957        }
33958
33959        it('should initialize to model', function() {
33960          expect(value.getText()).toContain('2013-10-22');
33961          expect(valid.getText()).toContain('myForm.input.$valid = true');
33962        });
33963
33964        it('should be invalid if empty', function() {
33965          setInput('');
33966          expect(value.getText()).toEqual('value =');
33967          expect(valid.getText()).toContain('myForm.input.$valid = false');
33968        });
33969
33970        it('should be invalid if over max', function() {
33971          setInput('2015-01-01');
33972          expect(value.getText()).toContain('');
33973          expect(valid.getText()).toContain('myForm.input.$valid = false');
33974        });
33975     </file>
33976     </example>
33977     */
33978  'date': createDateInputType('date', DATE_REGEXP,
33979         createDateParser(DATE_REGEXP, ['yyyy', 'MM', 'dd']),
33980         'yyyy-MM-dd'),
33981
33982   /**
33983    * @ngdoc input
33984    * @name input[datetime-local]
33985    *
33986    * @description
33987    * Input with datetime validation and transformation. In browsers that do not yet support
33988    * the HTML5 date input, a text element will be used. In that case, the text must be entered in a valid ISO-8601
33989    * local datetime format (yyyy-MM-ddTHH:mm:ss), for example: `2010-12-28T14:57:00`.
33990    *
33991    * The model must always be a Date object, otherwise Angular will throw an error.
33992    * Invalid `Date` objects (dates whose `getTime()` is `NaN`) will be rendered as an empty string.
33993    *
33994    * The timezone to be used to read/write the `Date` instance in the model can be defined using
33995    * {@link ng.directive:ngModelOptions ngModelOptions}. By default, this is the timezone of the browser.
33996    *
33997    * @param {string} ngModel Assignable angular expression to data-bind to.
33998    * @param {string=} name Property name of the form under which the control is published.
33999    * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`.
34000    *   This must be a valid ISO datetime format (yyyy-MM-ddTHH:mm:ss). You can also use interpolation
34001    *   inside this attribute (e.g. `min="{{minDatetimeLocal | date:'yyyy-MM-ddTHH:mm:ss'}}"`).
34002    *   Note that `min` will also add native HTML5 constraint validation.
34003    * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`.
34004    *   This must be a valid ISO datetime format (yyyy-MM-ddTHH:mm:ss). You can also use interpolation
34005    *   inside this attribute (e.g. `max="{{maxDatetimeLocal | date:'yyyy-MM-ddTHH:mm:ss'}}"`).
34006    *   Note that `max` will also add native HTML5 constraint validation.
34007    * @param {(date|string)=} ngMin Sets the `min` validation error key to the Date / ISO datetime string
34008    *   the `ngMin` expression evaluates to. Note that it does not set the `min` attribute.
34009    * @param {(date|string)=} ngMax Sets the `max` validation error key to the Date / ISO datetime string
34010    *   the `ngMax` expression evaluates to. Note that it does not set the `max` attribute.
34011    * @param {string=} required Sets `required` validation error key if the value is not entered.
34012    * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
34013    *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
34014    *    `required` when you want to data-bind to the `required` attribute.
34015    * @param {string=} ngChange Angular expression to be executed when input changes due to user
34016    *    interaction with the input element.
34017    *
34018    * @example
34019    <example name="datetimelocal-input-directive" module="dateExample">
34020    <file name="index.html">
34021      <script>
34022        angular.module('dateExample', [])
34023          .controller('DateController', ['$scope', function($scope) {
34024            $scope.example = {
34025              value: new Date(2010, 11, 28, 14, 57)
34026            };
34027          }]);
34028      </script>
34029      <form name="myForm" ng-controller="DateController as dateCtrl">
34030        <label for="exampleInput">Pick a date between in 2013:</label>
34031        <input type="datetime-local" id="exampleInput" name="input" ng-model="example.value"
34032            placeholder="yyyy-MM-ddTHH:mm:ss" min="2001-01-01T00:00:00" max="2013-12-31T00:00:00" required />
34033        <div role="alert">
34034          <span class="error" ng-show="myForm.input.$error.required">
34035              Required!</span>
34036          <span class="error" ng-show="myForm.input.$error.datetimelocal">
34037              Not a valid date!</span>
34038        </div>
34039        <tt>value = {{example.value | date: "yyyy-MM-ddTHH:mm:ss"}}</tt><br/>
34040        <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
34041        <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
34042        <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
34043        <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
34044      </form>
34045    </file>
34046    <file name="protractor.js" type="protractor">
34047      var value = element(by.binding('example.value | date: "yyyy-MM-ddTHH:mm:ss"'));
34048      var valid = element(by.binding('myForm.input.$valid'));
34049
34050      // currently protractor/webdriver does not support
34051      // sending keys to all known HTML5 input controls
34052      // for various browsers (https://github.com/angular/protractor/issues/562).
34053      function setInput(val) {
34054        // set the value of the element and force validation.
34055        var scr = "var ipt = document.getElementById('exampleInput'); " +
34056        "ipt.value = '" + val + "';" +
34057        "angular.element(ipt).scope().$apply(function(s) { s.myForm[ipt.name].$setViewValue('" + val + "'); });";
34058        browser.executeScript(scr);
34059      }
34060
34061      it('should initialize to model', function() {
34062        expect(value.getText()).toContain('2010-12-28T14:57:00');
34063        expect(valid.getText()).toContain('myForm.input.$valid = true');
34064      });
34065
34066      it('should be invalid if empty', function() {
34067        setInput('');
34068        expect(value.getText()).toEqual('value =');
34069        expect(valid.getText()).toContain('myForm.input.$valid = false');
34070      });
34071
34072      it('should be invalid if over max', function() {
34073        setInput('2015-01-01T23:59:00');
34074        expect(value.getText()).toContain('');
34075        expect(valid.getText()).toContain('myForm.input.$valid = false');
34076      });
34077    </file>
34078    </example>
34079    */
34080  'datetime-local': createDateInputType('datetimelocal', DATETIMELOCAL_REGEXP,
34081      createDateParser(DATETIMELOCAL_REGEXP, ['yyyy', 'MM', 'dd', 'HH', 'mm', 'ss', 'sss']),
34082      'yyyy-MM-ddTHH:mm:ss.sss'),
34083
34084  /**
34085   * @ngdoc input
34086   * @name input[time]
34087   *
34088   * @description
34089   * Input with time validation and transformation. In browsers that do not yet support
34090   * the HTML5 time input, a text element will be used. In that case, the text must be entered in a valid ISO-8601
34091   * local time format (HH:mm:ss), for example: `14:57:00`. Model must be a Date object. This binding will always output a
34092   * Date object to the model of January 1, 1970, or local date `new Date(1970, 0, 1, HH, mm, ss)`.
34093   *
34094   * The model must always be a Date object, otherwise Angular will throw an error.
34095   * Invalid `Date` objects (dates whose `getTime()` is `NaN`) will be rendered as an empty string.
34096   *
34097   * The timezone to be used to read/write the `Date` instance in the model can be defined using
34098   * {@link ng.directive:ngModelOptions ngModelOptions}. By default, this is the timezone of the browser.
34099   *
34100   * @param {string} ngModel Assignable angular expression to data-bind to.
34101   * @param {string=} name Property name of the form under which the control is published.
34102   * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`.
34103   *   This must be a valid ISO time format (HH:mm:ss). You can also use interpolation inside this
34104   *   attribute (e.g. `min="{{minTime | date:'HH:mm:ss'}}"`). Note that `min` will also add
34105   *   native HTML5 constraint validation.
34106   * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`.
34107   *   This must be a valid ISO time format (HH:mm:ss). You can also use interpolation inside this
34108   *   attribute (e.g. `max="{{maxTime | date:'HH:mm:ss'}}"`). Note that `max` will also add
34109   *   native HTML5 constraint validation.
34110   * @param {(date|string)=} ngMin Sets the `min` validation constraint to the Date / ISO time string the
34111   *   `ngMin` expression evaluates to. Note that it does not set the `min` attribute.
34112   * @param {(date|string)=} ngMax Sets the `max` validation constraint to the Date / ISO time string the
34113   *   `ngMax` expression evaluates to. Note that it does not set the `max` attribute.
34114   * @param {string=} required Sets `required` validation error key if the value is not entered.
34115   * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
34116   *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
34117   *    `required` when you want to data-bind to the `required` attribute.
34118   * @param {string=} ngChange Angular expression to be executed when input changes due to user
34119   *    interaction with the input element.
34120   *
34121   * @example
34122   <example name="time-input-directive" module="timeExample">
34123   <file name="index.html">
34124     <script>
34125      angular.module('timeExample', [])
34126        .controller('DateController', ['$scope', function($scope) {
34127          $scope.example = {
34128            value: new Date(1970, 0, 1, 14, 57, 0)
34129          };
34130        }]);
34131     </script>
34132     <form name="myForm" ng-controller="DateController as dateCtrl">
34133        <label for="exampleInput">Pick a time between 8am and 5pm:</label>
34134        <input type="time" id="exampleInput" name="input" ng-model="example.value"
34135            placeholder="HH:mm:ss" min="08:00:00" max="17:00:00" required />
34136        <div role="alert">
34137          <span class="error" ng-show="myForm.input.$error.required">
34138              Required!</span>
34139          <span class="error" ng-show="myForm.input.$error.time">
34140              Not a valid date!</span>
34141        </div>
34142        <tt>value = {{example.value | date: "HH:mm:ss"}}</tt><br/>
34143        <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
34144        <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
34145        <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
34146        <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
34147     </form>
34148   </file>
34149   <file name="protractor.js" type="protractor">
34150      var value = element(by.binding('example.value | date: "HH:mm:ss"'));
34151      var valid = element(by.binding('myForm.input.$valid'));
34152
34153      // currently protractor/webdriver does not support
34154      // sending keys to all known HTML5 input controls
34155      // for various browsers (https://github.com/angular/protractor/issues/562).
34156      function setInput(val) {
34157        // set the value of the element and force validation.
34158        var scr = "var ipt = document.getElementById('exampleInput'); " +
34159        "ipt.value = '" + val + "';" +
34160        "angular.element(ipt).scope().$apply(function(s) { s.myForm[ipt.name].$setViewValue('" + val + "'); });";
34161        browser.executeScript(scr);
34162      }
34163
34164      it('should initialize to model', function() {
34165        expect(value.getText()).toContain('14:57:00');
34166        expect(valid.getText()).toContain('myForm.input.$valid = true');
34167      });
34168
34169      it('should be invalid if empty', function() {
34170        setInput('');
34171        expect(value.getText()).toEqual('value =');
34172        expect(valid.getText()).toContain('myForm.input.$valid = false');
34173      });
34174
34175      it('should be invalid if over max', function() {
34176        setInput('23:59:00');
34177        expect(value.getText()).toContain('');
34178        expect(valid.getText()).toContain('myForm.input.$valid = false');
34179      });
34180   </file>
34181   </example>
34182   */
34183  'time': createDateInputType('time', TIME_REGEXP,
34184      createDateParser(TIME_REGEXP, ['HH', 'mm', 'ss', 'sss']),
34185     'HH:mm:ss.sss'),
34186
34187   /**
34188    * @ngdoc input
34189    * @name input[week]
34190    *
34191    * @description
34192    * Input with week-of-the-year validation and transformation to Date. In browsers that do not yet support
34193    * the HTML5 week input, a text element will be used. In that case, the text must be entered in a valid ISO-8601
34194    * week format (yyyy-W##), for example: `2013-W02`.
34195    *
34196    * The model must always be a Date object, otherwise Angular will throw an error.
34197    * Invalid `Date` objects (dates whose `getTime()` is `NaN`) will be rendered as an empty string.
34198    *
34199    * The timezone to be used to read/write the `Date` instance in the model can be defined using
34200    * {@link ng.directive:ngModelOptions ngModelOptions}. By default, this is the timezone of the browser.
34201    *
34202    * @param {string} ngModel Assignable angular expression to data-bind to.
34203    * @param {string=} name Property name of the form under which the control is published.
34204    * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`.
34205    *   This must be a valid ISO week format (yyyy-W##). You can also use interpolation inside this
34206    *   attribute (e.g. `min="{{minWeek | date:'yyyy-Www'}}"`). Note that `min` will also add
34207    *   native HTML5 constraint validation.
34208    * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`.
34209    *   This must be a valid ISO week format (yyyy-W##). You can also use interpolation inside this
34210    *   attribute (e.g. `max="{{maxWeek | date:'yyyy-Www'}}"`). Note that `max` will also add
34211    *   native HTML5 constraint validation.
34212    * @param {(date|string)=} ngMin Sets the `min` validation constraint to the Date / ISO week string
34213    *   the `ngMin` expression evaluates to. Note that it does not set the `min` attribute.
34214    * @param {(date|string)=} ngMax Sets the `max` validation constraint to the Date / ISO week string
34215    *   the `ngMax` expression evaluates to. Note that it does not set the `max` attribute.
34216    * @param {string=} required Sets `required` validation error key if the value is not entered.
34217    * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
34218    *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
34219    *    `required` when you want to data-bind to the `required` attribute.
34220    * @param {string=} ngChange Angular expression to be executed when input changes due to user
34221    *    interaction with the input element.
34222    *
34223    * @example
34224    <example name="week-input-directive" module="weekExample">
34225    <file name="index.html">
34226      <script>
34227      angular.module('weekExample', [])
34228        .controller('DateController', ['$scope', function($scope) {
34229          $scope.example = {
34230            value: new Date(2013, 0, 3)
34231          };
34232        }]);
34233      </script>
34234      <form name="myForm" ng-controller="DateController as dateCtrl">
34235        <label>Pick a date between in 2013:
34236          <input id="exampleInput" type="week" name="input" ng-model="example.value"
34237                 placeholder="YYYY-W##" min="2012-W32"
34238                 max="2013-W52" required />
34239        </label>
34240        <div role="alert">
34241          <span class="error" ng-show="myForm.input.$error.required">
34242              Required!</span>
34243          <span class="error" ng-show="myForm.input.$error.week">
34244              Not a valid date!</span>
34245        </div>
34246        <tt>value = {{example.value | date: "yyyy-Www"}}</tt><br/>
34247        <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
34248        <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
34249        <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
34250        <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
34251      </form>
34252    </file>
34253    <file name="protractor.js" type="protractor">
34254      var value = element(by.binding('example.value | date: "yyyy-Www"'));
34255      var valid = element(by.binding('myForm.input.$valid'));
34256
34257      // currently protractor/webdriver does not support
34258      // sending keys to all known HTML5 input controls
34259      // for various browsers (https://github.com/angular/protractor/issues/562).
34260      function setInput(val) {
34261        // set the value of the element and force validation.
34262        var scr = "var ipt = document.getElementById('exampleInput'); " +
34263        "ipt.value = '" + val + "';" +
34264        "angular.element(ipt).scope().$apply(function(s) { s.myForm[ipt.name].$setViewValue('" + val + "'); });";
34265        browser.executeScript(scr);
34266      }
34267
34268      it('should initialize to model', function() {
34269        expect(value.getText()).toContain('2013-W01');
34270        expect(valid.getText()).toContain('myForm.input.$valid = true');
34271      });
34272
34273      it('should be invalid if empty', function() {
34274        setInput('');
34275        expect(value.getText()).toEqual('value =');
34276        expect(valid.getText()).toContain('myForm.input.$valid = false');
34277      });
34278
34279      it('should be invalid if over max', function() {
34280        setInput('2015-W01');
34281        expect(value.getText()).toContain('');
34282        expect(valid.getText()).toContain('myForm.input.$valid = false');
34283      });
34284    </file>
34285    </example>
34286    */
34287  'week': createDateInputType('week', WEEK_REGEXP, weekParser, 'yyyy-Www'),
34288
34289  /**
34290   * @ngdoc input
34291   * @name input[month]
34292   *
34293   * @description
34294   * Input with month validation and transformation. In browsers that do not yet support
34295   * the HTML5 month input, a text element will be used. In that case, the text must be entered in a valid ISO-8601
34296   * month format (yyyy-MM), for example: `2009-01`.
34297   *
34298   * The model must always be a Date object, otherwise Angular will throw an error.
34299   * Invalid `Date` objects (dates whose `getTime()` is `NaN`) will be rendered as an empty string.
34300   * If the model is not set to the first of the month, the next view to model update will set it
34301   * to the first of the month.
34302   *
34303   * The timezone to be used to read/write the `Date` instance in the model can be defined using
34304   * {@link ng.directive:ngModelOptions ngModelOptions}. By default, this is the timezone of the browser.
34305   *
34306   * @param {string} ngModel Assignable angular expression to data-bind to.
34307   * @param {string=} name Property name of the form under which the control is published.
34308   * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`.
34309   *   This must be a valid ISO month format (yyyy-MM). You can also use interpolation inside this
34310   *   attribute (e.g. `min="{{minMonth | date:'yyyy-MM'}}"`). Note that `min` will also add
34311   *   native HTML5 constraint validation.
34312   * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`.
34313   *   This must be a valid ISO month format (yyyy-MM). You can also use interpolation inside this
34314   *   attribute (e.g. `max="{{maxMonth | date:'yyyy-MM'}}"`). Note that `max` will also add
34315   *   native HTML5 constraint validation.
34316   * @param {(date|string)=} ngMin Sets the `min` validation constraint to the Date / ISO week string
34317   *   the `ngMin` expression evaluates to. Note that it does not set the `min` attribute.
34318   * @param {(date|string)=} ngMax Sets the `max` validation constraint to the Date / ISO week string
34319   *   the `ngMax` expression evaluates to. Note that it does not set the `max` attribute.
34320
34321   * @param {string=} required Sets `required` validation error key if the value is not entered.
34322   * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
34323   *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
34324   *    `required` when you want to data-bind to the `required` attribute.
34325   * @param {string=} ngChange Angular expression to be executed when input changes due to user
34326   *    interaction with the input element.
34327   *
34328   * @example
34329   <example name="month-input-directive" module="monthExample">
34330   <file name="index.html">
34331     <script>
34332      angular.module('monthExample', [])
34333        .controller('DateController', ['$scope', function($scope) {
34334          $scope.example = {
34335            value: new Date(2013, 9, 1)
34336          };
34337        }]);
34338     </script>
34339     <form name="myForm" ng-controller="DateController as dateCtrl">
34340       <label for="exampleInput">Pick a month in 2013:</label>
34341       <input id="exampleInput" type="month" name="input" ng-model="example.value"
34342          placeholder="yyyy-MM" min="2013-01" max="2013-12" required />
34343       <div role="alert">
34344         <span class="error" ng-show="myForm.input.$error.required">
34345            Required!</span>
34346         <span class="error" ng-show="myForm.input.$error.month">
34347            Not a valid month!</span>
34348       </div>
34349       <tt>value = {{example.value | date: "yyyy-MM"}}</tt><br/>
34350       <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
34351       <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
34352       <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
34353       <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
34354     </form>
34355   </file>
34356   <file name="protractor.js" type="protractor">
34357      var value = element(by.binding('example.value | date: "yyyy-MM"'));
34358      var valid = element(by.binding('myForm.input.$valid'));
34359
34360      // currently protractor/webdriver does not support
34361      // sending keys to all known HTML5 input controls
34362      // for various browsers (https://github.com/angular/protractor/issues/562).
34363      function setInput(val) {
34364        // set the value of the element and force validation.
34365        var scr = "var ipt = document.getElementById('exampleInput'); " +
34366        "ipt.value = '" + val + "';" +
34367        "angular.element(ipt).scope().$apply(function(s) { s.myForm[ipt.name].$setViewValue('" + val + "'); });";
34368        browser.executeScript(scr);
34369      }
34370
34371      it('should initialize to model', function() {
34372        expect(value.getText()).toContain('2013-10');
34373        expect(valid.getText()).toContain('myForm.input.$valid = true');
34374      });
34375
34376      it('should be invalid if empty', function() {
34377        setInput('');
34378        expect(value.getText()).toEqual('value =');
34379        expect(valid.getText()).toContain('myForm.input.$valid = false');
34380      });
34381
34382      it('should be invalid if over max', function() {
34383        setInput('2015-01');
34384        expect(value.getText()).toContain('');
34385        expect(valid.getText()).toContain('myForm.input.$valid = false');
34386      });
34387   </file>
34388   </example>
34389   */
34390  'month': createDateInputType('month', MONTH_REGEXP,
34391     createDateParser(MONTH_REGEXP, ['yyyy', 'MM']),
34392     'yyyy-MM'),
34393
34394  /**
34395   * @ngdoc input
34396   * @name input[number]
34397   *
34398   * @description
34399   * Text input with number validation and transformation. Sets the `number` validation
34400   * error if not a valid number.
34401   *
34402   * <div class="alert alert-warning">
34403   * The model must always be of type `number` otherwise Angular will throw an error.
34404   * Be aware that a string containing a number is not enough. See the {@link ngModel:numfmt}
34405   * error docs for more information and an example of how to convert your model if necessary.
34406   * </div>
34407   *
34408   * ## Issues with HTML5 constraint validation
34409   *
34410   * In browsers that follow the
34411   * [HTML5 specification](https://html.spec.whatwg.org/multipage/forms.html#number-state-%28type=number%29),
34412   * `input[number]` does not work as expected with {@link ngModelOptions `ngModelOptions.allowInvalid`}.
34413   * If a non-number is entered in the input, the browser will report the value as an empty string,
34414   * which means the view / model values in `ngModel` and subsequently the scope value
34415   * will also be an empty string.
34416   *
34417   *
34418   * @param {string} ngModel Assignable angular expression to data-bind to.
34419   * @param {string=} name Property name of the form under which the control is published.
34420   * @param {string=} min Sets the `min` validation error key if the value entered is less than `min`.
34421   *    Can be interpolated.
34422   * @param {string=} max Sets the `max` validation error key if the value entered is greater than `max`.
34423   *    Can be interpolated.
34424   * @param {string=} ngMin Like `min`, sets the `min` validation error key if the value entered is less than `ngMin`,
34425   *    but does not trigger HTML5 native validation. Takes an expression.
34426   * @param {string=} ngMax Like `max`, sets the `max` validation error key if the value entered is greater than `ngMax`,
34427   *    but does not trigger HTML5 native validation. Takes an expression.
34428   * @param {string=} step Sets the `step` validation error key if the value entered does not fit the `step` constraint.
34429   *    Can be interpolated.
34430   * @param {string=} ngStep Like `step`, sets the `step` validation error key if the value entered does not fit the `ngStep` constraint,
34431   *    but does not trigger HTML5 native validation. Takes an expression.
34432   * @param {string=} required Sets `required` validation error key if the value is not entered.
34433   * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
34434   *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
34435   *    `required` when you want to data-bind to the `required` attribute.
34436   * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
34437   *    minlength.
34438   * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
34439   *    maxlength. Setting the attribute to a negative or non-numeric value, allows view values of
34440   *    any length.
34441   * @param {string=} pattern Similar to `ngPattern` except that the attribute value is the actual string
34442   *    that contains the regular expression body that will be converted to a regular expression
34443   *    as in the ngPattern directive.
34444   * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel {@link ngModel.NgModelController#$viewValue $viewValue}
34445   *    does not match a RegExp found by evaluating the Angular expression given in the attribute value.
34446   *    If the expression evaluates to a RegExp object, then this is used directly.
34447   *    If the expression evaluates to a string, then it will be converted to a RegExp
34448   *    after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to
34449   *    `new RegExp('^abc$')`.<br />
34450   *    **Note:** Avoid using the `g` flag on the RegExp, as it will cause each successive search to
34451   *    start at the index of the last search's match, thus not taking the whole input value into
34452   *    account.
34453   * @param {string=} ngChange Angular expression to be executed when input changes due to user
34454   *    interaction with the input element.
34455   *
34456   * @example
34457      <example name="number-input-directive" module="numberExample">
34458        <file name="index.html">
34459         <script>
34460           angular.module('numberExample', [])
34461             .controller('ExampleController', ['$scope', function($scope) {
34462               $scope.example = {
34463                 value: 12
34464               };
34465             }]);
34466         </script>
34467         <form name="myForm" ng-controller="ExampleController">
34468           <label>Number:
34469             <input type="number" name="input" ng-model="example.value"
34470                    min="0" max="99" required>
34471          </label>
34472           <div role="alert">
34473             <span class="error" ng-show="myForm.input.$error.required">
34474               Required!</span>
34475             <span class="error" ng-show="myForm.input.$error.number">
34476               Not valid number!</span>
34477           </div>
34478           <tt>value = {{example.value}}</tt><br/>
34479           <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
34480           <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
34481           <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
34482           <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
34483          </form>
34484        </file>
34485        <file name="protractor.js" type="protractor">
34486          var value = element(by.binding('example.value'));
34487          var valid = element(by.binding('myForm.input.$valid'));
34488          var input = element(by.model('example.value'));
34489
34490          it('should initialize to model', function() {
34491            expect(value.getText()).toContain('12');
34492            expect(valid.getText()).toContain('true');
34493          });
34494
34495          it('should be invalid if empty', function() {
34496            input.clear();
34497            input.sendKeys('');
34498            expect(value.getText()).toEqual('value =');
34499            expect(valid.getText()).toContain('false');
34500          });
34501
34502          it('should be invalid if over max', function() {
34503            input.clear();
34504            input.sendKeys('123');
34505            expect(value.getText()).toEqual('value =');
34506            expect(valid.getText()).toContain('false');
34507          });
34508        </file>
34509      </example>
34510   */
34511  'number': numberInputType,
34512
34513
34514  /**
34515   * @ngdoc input
34516   * @name input[url]
34517   *
34518   * @description
34519   * Text input with URL validation. Sets the `url` validation error key if the content is not a
34520   * valid URL.
34521   *
34522   * <div class="alert alert-warning">
34523   * **Note:** `input[url]` uses a regex to validate urls that is derived from the regex
34524   * used in Chromium. If you need stricter validation, you can use `ng-pattern` or modify
34525   * the built-in validators (see the {@link guide/forms Forms guide})
34526   * </div>
34527   *
34528   * @param {string} ngModel Assignable angular expression to data-bind to.
34529   * @param {string=} name Property name of the form under which the control is published.
34530   * @param {string=} required Sets `required` validation error key if the value is not entered.
34531   * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
34532   *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
34533   *    `required` when you want to data-bind to the `required` attribute.
34534   * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
34535   *    minlength.
34536   * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
34537   *    maxlength. Setting the attribute to a negative or non-numeric value, allows view values of
34538   *    any length.
34539   * @param {string=} pattern Similar to `ngPattern` except that the attribute value is the actual string
34540   *    that contains the regular expression body that will be converted to a regular expression
34541   *    as in the ngPattern directive.
34542   * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel {@link ngModel.NgModelController#$viewValue $viewValue}
34543   *    does not match a RegExp found by evaluating the Angular expression given in the attribute value.
34544   *    If the expression evaluates to a RegExp object, then this is used directly.
34545   *    If the expression evaluates to a string, then it will be converted to a RegExp
34546   *    after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to
34547   *    `new RegExp('^abc$')`.<br />
34548   *    **Note:** Avoid using the `g` flag on the RegExp, as it will cause each successive search to
34549   *    start at the index of the last search's match, thus not taking the whole input value into
34550   *    account.
34551   * @param {string=} ngChange Angular expression to be executed when input changes due to user
34552   *    interaction with the input element.
34553   *
34554   * @example
34555      <example name="url-input-directive" module="urlExample">
34556        <file name="index.html">
34557         <script>
34558           angular.module('urlExample', [])
34559             .controller('ExampleController', ['$scope', function($scope) {
34560               $scope.url = {
34561                 text: 'http://google.com'
34562               };
34563             }]);
34564         </script>
34565         <form name="myForm" ng-controller="ExampleController">
34566           <label>URL:
34567             <input type="url" name="input" ng-model="url.text" required>
34568           <label>
34569           <div role="alert">
34570             <span class="error" ng-show="myForm.input.$error.required">
34571               Required!</span>
34572             <span class="error" ng-show="myForm.input.$error.url">
34573               Not valid url!</span>
34574           </div>
34575           <tt>text = {{url.text}}</tt><br/>
34576           <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
34577           <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
34578           <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
34579           <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
34580           <tt>myForm.$error.url = {{!!myForm.$error.url}}</tt><br/>
34581          </form>
34582        </file>
34583        <file name="protractor.js" type="protractor">
34584          var text = element(by.binding('url.text'));
34585          var valid = element(by.binding('myForm.input.$valid'));
34586          var input = element(by.model('url.text'));
34587
34588          it('should initialize to model', function() {
34589            expect(text.getText()).toContain('http://google.com');
34590            expect(valid.getText()).toContain('true');
34591          });
34592
34593          it('should be invalid if empty', function() {
34594            input.clear();
34595            input.sendKeys('');
34596
34597            expect(text.getText()).toEqual('text =');
34598            expect(valid.getText()).toContain('false');
34599          });
34600
34601          it('should be invalid if not url', function() {
34602            input.clear();
34603            input.sendKeys('box');
34604
34605            expect(valid.getText()).toContain('false');
34606          });
34607        </file>
34608      </example>
34609   */
34610  'url': urlInputType,
34611
34612
34613  /**
34614   * @ngdoc input
34615   * @name input[email]
34616   *
34617   * @description
34618   * Text input with email validation. Sets the `email` validation error key if not a valid email
34619   * address.
34620   *
34621   * <div class="alert alert-warning">
34622   * **Note:** `input[email]` uses a regex to validate email addresses that is derived from the regex
34623   * used in Chromium. If you need stricter validation (e.g. requiring a top-level domain), you can
34624   * use `ng-pattern` or modify the built-in validators (see the {@link guide/forms Forms guide})
34625   * </div>
34626   *
34627   * @param {string} ngModel Assignable angular expression to data-bind to.
34628   * @param {string=} name Property name of the form under which the control is published.
34629   * @param {string=} required Sets `required` validation error key if the value is not entered.
34630   * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
34631   *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
34632   *    `required` when you want to data-bind to the `required` attribute.
34633   * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
34634   *    minlength.
34635   * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
34636   *    maxlength. Setting the attribute to a negative or non-numeric value, allows view values of
34637   *    any length.
34638   * @param {string=} pattern Similar to `ngPattern` except that the attribute value is the actual string
34639   *    that contains the regular expression body that will be converted to a regular expression
34640   *    as in the ngPattern directive.
34641   * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel {@link ngModel.NgModelController#$viewValue $viewValue}
34642   *    does not match a RegExp found by evaluating the Angular expression given in the attribute value.
34643   *    If the expression evaluates to a RegExp object, then this is used directly.
34644   *    If the expression evaluates to a string, then it will be converted to a RegExp
34645   *    after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to
34646   *    `new RegExp('^abc$')`.<br />
34647   *    **Note:** Avoid using the `g` flag on the RegExp, as it will cause each successive search to
34648   *    start at the index of the last search's match, thus not taking the whole input value into
34649   *    account.
34650   * @param {string=} ngChange Angular expression to be executed when input changes due to user
34651   *    interaction with the input element.
34652   *
34653   * @example
34654      <example name="email-input-directive" module="emailExample">
34655        <file name="index.html">
34656         <script>
34657           angular.module('emailExample', [])
34658             .controller('ExampleController', ['$scope', function($scope) {
34659               $scope.email = {
34660                 text: '[email protected]'
34661               };
34662             }]);
34663         </script>
34664           <form name="myForm" ng-controller="ExampleController">
34665             <label>Email:
34666               <input type="email" name="input" ng-model="email.text" required>
34667             </label>
34668             <div role="alert">
34669               <span class="error" ng-show="myForm.input.$error.required">
34670                 Required!</span>
34671               <span class="error" ng-show="myForm.input.$error.email">
34672                 Not valid email!</span>
34673             </div>
34674             <tt>text = {{email.text}}</tt><br/>
34675             <tt>myForm.input.$valid = {{myForm.input.$valid}}</tt><br/>
34676             <tt>myForm.input.$error = {{myForm.input.$error}}</tt><br/>
34677             <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
34678             <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
34679             <tt>myForm.$error.email = {{!!myForm.$error.email}}</tt><br/>
34680           </form>
34681         </file>
34682        <file name="protractor.js" type="protractor">
34683          var text = element(by.binding('email.text'));
34684          var valid = element(by.binding('myForm.input.$valid'));
34685          var input = element(by.model('email.text'));
34686
34687          it('should initialize to model', function() {
34688            expect(text.getText()).toContain('[email protected]');
34689            expect(valid.getText()).toContain('true');
34690          });
34691
34692          it('should be invalid if empty', function() {
34693            input.clear();
34694            input.sendKeys('');
34695            expect(text.getText()).toEqual('text =');
34696            expect(valid.getText()).toContain('false');
34697          });
34698
34699          it('should be invalid if not email', function() {
34700            input.clear();
34701            input.sendKeys('xxx');
34702
34703            expect(valid.getText()).toContain('false');
34704          });
34705        </file>
34706      </example>
34707   */
34708  'email': emailInputType,
34709
34710
34711  /**
34712   * @ngdoc input
34713   * @name input[radio]
34714   *
34715   * @description
34716   * HTML radio button.
34717   *
34718   * @param {string} ngModel Assignable angular expression to data-bind to.
34719   * @param {string} value The value to which the `ngModel` expression should be set when selected.
34720   *    Note that `value` only supports `string` values, i.e. the scope model needs to be a string,
34721   *    too. Use `ngValue` if you need complex models (`number`, `object`, ...).
34722   * @param {string=} name Property name of the form under which the control is published.
34723   * @param {string=} ngChange Angular expression to be executed when input changes due to user
34724   *    interaction with the input element.
34725   * @param {string} ngValue Angular expression to which `ngModel` will be be set when the radio
34726   *    is selected. Should be used instead of the `value` attribute if you need
34727   *    a non-string `ngModel` (`boolean`, `array`, ...).
34728   *
34729   * @example
34730      <example name="radio-input-directive" module="radioExample">
34731        <file name="index.html">
34732         <script>
34733           angular.module('radioExample', [])
34734             .controller('ExampleController', ['$scope', function($scope) {
34735               $scope.color = {
34736                 name: 'blue'
34737               };
34738               $scope.specialValue = {
34739                 "id": "12345",
34740                 "value": "green"
34741               };
34742             }]);
34743         </script>
34744         <form name="myForm" ng-controller="ExampleController">
34745           <label>
34746             <input type="radio" ng-model="color.name" value="red">
34747             Red
34748           </label><br/>
34749           <label>
34750             <input type="radio" ng-model="color.name" ng-value="specialValue">
34751             Green
34752           </label><br/>
34753           <label>
34754             <input type="radio" ng-model="color.name" value="blue">
34755             Blue
34756           </label><br/>
34757           <tt>color = {{color.name | json}}</tt><br/>
34758          </form>
34759          Note that `ng-value="specialValue"` sets radio item's value to be the value of `$scope.specialValue`.
34760        </file>
34761        <file name="protractor.js" type="protractor">
34762          it('should change state', function() {
34763            var inputs = element.all(by.model('color.name'));
34764            var color = element(by.binding('color.name'));
34765
34766            expect(color.getText()).toContain('blue');
34767
34768            inputs.get(0).click();
34769            expect(color.getText()).toContain('red');
34770
34771            inputs.get(1).click();
34772            expect(color.getText()).toContain('green');
34773          });
34774        </file>
34775      </example>
34776   */
34777  'radio': radioInputType,
34778
34779  /**
34780   * @ngdoc input
34781   * @name input[range]
34782   *
34783   * @description
34784   * Native range input with validation and transformation.
34785   *
34786   * The model for the range input must always be a `Number`.
34787   *
34788   * IE9 and other browsers that do not support the `range` type fall back
34789   * to a text input without any default values for `min`, `max` and `step`. Model binding,
34790   * validation and number parsing are nevertheless supported.
34791   *
34792   * Browsers that support range (latest Chrome, Safari, Firefox, Edge) treat `input[range]`
34793   * in a way that never allows the input to hold an invalid value. That means:
34794   * - any non-numerical value is set to `(max + min) / 2`.
34795   * - any numerical value that is less than the current min val, or greater than the current max val
34796   * is set to the min / max val respectively.
34797   * - additionally, the current `step` is respected, so the nearest value that satisfies a step
34798   * is used.
34799   *
34800   * See the [HTML Spec on input[type=range]](https://www.w3.org/TR/html5/forms.html#range-state-(type=range))
34801   * for more info.
34802   *
34803   * This has the following consequences for Angular:
34804   *
34805   * Since the element value should always reflect the current model value, a range input
34806   * will set the bound ngModel expression to the value that the browser has set for the
34807   * input element. For example, in the following input `<input type="range" ng-model="model.value">`,
34808   * if the application sets `model.value = null`, the browser will set the input to `'50'`.
34809   * Angular will then set the model to `50`, to prevent input and model value being out of sync.
34810   *
34811   * That means the model for range will immediately be set to `50` after `ngModel` has been
34812   * initialized. It also means a range input can never have the required error.
34813   *
34814   * This does not only affect changes to the model value, but also to the values of the `min`,
34815   * `max`, and `step` attributes. When these change in a way that will cause the browser to modify
34816   * the input value, Angular will also update the model value.
34817   *
34818   * Automatic value adjustment also means that a range input element can never have the `required`,
34819   * `min`, or `max` errors.
34820   *
34821   * However, `step` is currently only fully implemented by Firefox. Other browsers have problems
34822   * when the step value changes dynamically - they do not adjust the element value correctly, but
34823   * instead may set the `stepMismatch` error. If that's the case, the Angular will set the `step`
34824   * error on the input, and set the model to `undefined`.
34825   *
34826   * Note that `input[range]` is not compatible with`ngMax`, `ngMin`, and `ngStep`, because they do
34827   * not set the `min` and `max` attributes, which means that the browser won't automatically adjust
34828   * the input value based on their values, and will always assume min = 0, max = 100, and step = 1.
34829   *
34830   * @param {string}  ngModel Assignable angular expression to data-bind to.
34831   * @param {string=} name Property name of the form under which the control is published.
34832   * @param {string=} min Sets the `min` validation to ensure that the value entered is greater
34833   *                  than `min`. Can be interpolated.
34834   * @param {string=} max Sets the `max` validation to ensure that the value entered is less than `max`.
34835   *                  Can be interpolated.
34836   * @param {string=} step Sets the `step` validation to ensure that the value entered matches the `step`
34837   *                  Can be interpolated.
34838   * @param {string=} ngChange Angular expression to be executed when the ngModel value changes due
34839   *
vendor: 2,634 bytes, lines 34839-34905
34839                  to user interaction with the input element.
34840   * @param {expression=} ngChecked If the expression is truthy, then the `checked` attribute will be set on the
34841   *                      element. **Note** : `ngChecked` should not be used alongside `ngModel`.
34842   *                      Checkout {@link ng.directive:ngChecked ngChecked} for usage.
34843   *
34844   * @example
34845      <example name="range-input-directive" module="rangeExample">
34846        <file name="index.html">
34847          <script>
34848            angular.module('rangeExample', [])
34849              .controller('ExampleController', ['$scope', function($scope) {
34850                $scope.value = 75;
34851                $scope.min = 10;
34852                $scope.max = 90;
34853              }]);
34854          </script>
34855          <form name="myForm" ng-controller="ExampleController">
34856
34857            Model as range: <input type="range" name="range" ng-model="value" min="{{min}}"  max="{{max}}">
34858            <hr>
34859            Model as number: <input type="number" ng-model="value"><br>
34860            Min: <input type="number" ng-model="min"><br>
34861            Max: <input type="number" ng-model="max"><br>
34862            value = <code>{{value}}</code><br/>
34863            myForm.range.$valid = <code>{{myForm.range.$valid}}</code><br/>
34864            myForm.range.$error = <code>{{myForm.range.$error}}</code>
34865          </form>
34866        </file>
34867      </example>
34868
34869   * ## Range Input with ngMin & ngMax attributes
34870
34871   * @example
34872      <example name="range-input-directive-ng" module="rangeExample">
34873        <file name="index.html">
34874          <script>
34875            angular.module('rangeExample', [])
34876              .controller('ExampleController', ['$scope', function($scope) {
34877                $scope.value = 75;
34878                $scope.min = 10;
34879                $scope.max = 90;
34880              }]);
34881          </script>
34882          <form name="myForm" ng-controller="ExampleController">
34883            Model as range: <input type="range" name="range" ng-model="value" ng-min="min" ng-max="max">
34884            <hr>
34885            Model as number: <input type="number" ng-model="value"><br>
34886            Min: <input type="number" ng-model="min"><br>
34887            Max: <input type="number" ng-model="max"><br>
34888            value = <code>{{value}}</code><br/>
34889            myForm.range.$valid = <code>{{myForm.range.$valid}}</code><br/>
34890            myForm.range.$error = <code>{{myForm.range.$error}}</code>
34891          </form>
34892        </file>
34893      </example>
34894
34895   */
34896  'range': rangeInputType,
34897
34898  /**
34899   * @ngdoc input
34900   * @name input[checkbox]
34901   *
34902   * @description
34903   * HTML checkbox.
34904   *
34905   * @param {string} ngModel Assignable 
34905angular expression to data-bind to.
34906   * @param {string=} name Property name of the form under which the control is published.
34907   * @param {expression=} ngTrueValue The value to which the expression should be set when selected.
34908   * @param {expression=} ngFalseValue The value to which the expression should be set when not selected.
34909   * @param {string=} ngChange Angular expression to be executed when input changes due to user
34910   *    interaction with the input element.
34911   *
34912   * @example
34913      <example name="checkbox-input-directive" module="checkboxExample">
34914        <file name="index.html">
34915         <script>
34916           angular.module('checkboxExample', [])
34917             .controller('ExampleController', ['$scope', function($scope) {
34918               $scope.checkboxModel = {
34919                value1 : true,
34920                value2 : 'YES'
34921              };
34922             }]);
34923         </script>
34924         <form name="myForm" ng-controller="ExampleController">
34925           <label>Value1:
34926             <input type="checkbox" ng-model="checkboxModel.value1">
34927           </label><br/>
34928           <label>Value2:
34929             <input type="checkbox" ng-model="checkboxModel.value2"
34930                    ng-true-value="'YES'" ng-false-value="'NO'">
34931            </label><br/>
34932           <tt>value1 = {{checkboxModel.value1}}</tt><br/>
34933           <tt>value2 = {{checkboxModel.value2}}</tt><br/>
34934          </form>
34935        </file>
34936        <file name="protractor.js" type="protractor">
34937          it('should change state', function() {
34938            var value1 = element(by.binding('checkboxModel.value1'));
34939            var value2 = element(by.binding('checkboxModel.value2'));
34940
34941            expect(value1.getText()).toContain('true');
34942            expect(value2.getText()).toContain('YES');
34943
34944            element(by.model('checkboxModel.value1')).click();
34945            element(by.model('checkboxModel.value2')).click();
34946
34947            expect(value1.getText()).toContain('false');
34948            expect(value2.getText()).toContain('NO');
34949          });
34950        </file>
34951      </example>
34952   */
34953  'checkbox': checkboxInputType,
34954
34955  'hidden': noop,
34956  'button': noop,
34957  'submit': noop,
34958  'reset': noop,
34959  'file': noop
34960};
34961
34962function stringBasedInputType(ctrl) {
34963  ctrl.$formatters.push(function(value) {
34964    return ctrl.$isEmpty(value) ? value : value.toString();
34965  });
34966}
34967
34968function textInputType(scope, element, attr, ctrl, $sniffer, $browser) {
34969  baseInputType(scope, element, attr, ctrl, $sniffer, $browser);
34970  stringBasedInputType(ctrl);
34971}
34972
34973function baseInputType(scope, element, attr, ctrl, $sniffer, $browser) {
34974  var type = lowercase(element[0].type);
34975
34976  // In composition mode, users are still inputting intermediate text buffer,
34977  // hold the listener until composition is done.
34978  // More about composition events: https://developer.mozilla.org/en-US/docs/Web/API/CompositionEvent
34979  if (!$sniffer.android) {
34980    var composing = false;
34981
34982    element.on('compositionstart', function() {
34983      composing = true;
34984    });
34985
34986    element.on('compositionend', function() {
34987      composing = false;
34988      listener();
34989    });
34990  }
34991
34992  var timeout;
34993
34994  var listener = function(ev) {
34995    if (timeout) {
34996      $browser.defer.cancel(timeout);
34997      timeout = null;
34998    }
34999    if (composing) return;
35000    var value = element.val(),
35001        event = ev && ev.type;
35002
35003    // By default we will trim the value
35004    // If the attribute ng-trim exists we will avoid trimming
35005    // If input type is 'password', the value is never trimmed
35006    if (type !== 'password' && (!attr.ngTrim || attr.ngTrim !== 'false')) {
35007      value = trim(value);
35008    }
35009
35010    // If a control is suffering from bad input (due to native validators), browsers discard its
35011    // value, so it may be necessary to revalidate (by calling $setViewValue again) even if the
35012    // control's value is the same empty value twice in a row.
35013    if (ctrl.$viewValue !== value || (value === '' && ctrl.$$hasNativeValidators)) {
35014      ctrl.$setViewValue(value, event);
35015    }
35016  };
35017
35018  // if the browser does support "input" event, we are fine - except on IE9 which doesn't fire the
35019  // input event on backspace, delete or cut
35020  if ($sniffer.hasEvent('input')) {
35021    element.on('input', listener);
35022  } else {
35023    var deferListener = function(ev, input, origValue) {
35024      if (!timeout) {
35025        timeout = $browser.defer(function() {
35026          timeout = null;
35027          if (!input || input.value !== origValue) {
35028            listener(ev);
35029          }
35030        });
35031      }
35032    };
35033
35034    element.on('keydown', /** @this */ function(event) {
35035      var key = event.keyCode;
35036
35037      // ignore
35038      //    command            modifiers                   arrows
35039      if (key === 91 || (15 < key && key < 19) || (37 <= key && key <= 40)) return;
35040
35041      deferListener(event, this, this.value);
35042    });
35043
35044    // if user modifies input value using context menu in IE, we need "paste" and "cut" events to catch it
35045    if ($sniffer.hasEvent('paste')) {
35046      element.on('paste cut', deferListener);
35047    }
35048  }
35049
35050  // if user paste into input using mouse on older browser
35051  // or form autocomplete on newer browser, we need "change" event to catch it
35052  element.on('change', listener);
35053
35054  // Some native input types (date-family) have the ability to change validity without
35055  // firing any input/change events.
35056  // For these event types, when native validators are present and the browser supports the type,
35057  // check for validity changes on various DOM events.
35058  if (PARTIAL_VALIDATION_TYPES[type] && ctrl.$$hasNativeValidators && type === attr.type) {
35059    element.on(PARTIAL_VALIDATION_EVENTS, /** @this */ function(ev) {
35060      if (!timeout) {
vendor: 17,297 bytes, lines 35061-35597
35061        var validity = this[VALIDITY_STATE_PROPERTY];
35062        var origBadInput = validity.badInput;
35063        var origTypeMismatch = validity.typeMismatch;
35064        timeout = $browser.defer(function() {
35065          timeout = null;
35066          if (validity.badInput !== origBadInput || validity.typeMismatch !== origTypeMismatch) {
35067            listener(ev);
35068          }
35069        });
35070      }
35071    });
35072  }
35073
35074  ctrl.$render = function() {
35075    // Workaround for Firefox validation #12102.
35076    var value = ctrl.$isEmpty(ctrl.$viewValue) ? '' : ctrl.$viewValue;
35077    if (element.val() !== value) {
35078      element.val(value);
35079    }
35080  };
35081}
35082
35083function weekParser(isoWeek, existingDate) {
35084  if (isDate(isoWeek)) {
35085    return isoWeek;
35086  }
35087
35088  if (isString(isoWeek)) {
35089    WEEK_REGEXP.lastIndex = 0;
35090    var parts = WEEK_REGEXP.exec(isoWeek);
35091    if (parts) {
35092      var year = +parts[1],
35093          week = +parts[2],
35094          hours = 0,
35095          minutes = 0,
35096          seconds = 0,
35097          milliseconds = 0,
35098          firstThurs = getFirstThursdayOfYear(year),
35099          addDays = (week - 1) * 7;
35100
35101      if (existingDate) {
35102        hours = existingDate.getHours();
35103        minutes = existingDate.getMinutes();
35104        seconds = existingDate.getSeconds();
35105        milliseconds = existingDate.getMilliseconds();
35106      }
35107
35108      return new Date(year, 0, firstThurs.getDate() + addDays, hours, minutes, seconds, milliseconds);
35109    }
35110  }
35111
35112  return NaN;
35113}
35114
35115function createDateParser(regexp, mapping) {
35116  return function(iso, date) {
35117    var parts, map;
35118
35119    if (isDate(iso)) {
35120      return iso;
35121    }
35122
35123    if (isString(iso)) {
35124      // When a date is JSON'ified to wraps itself inside of an extra
35125      // set of double quotes. This makes the date parsing code unable
35126      // to match the date string and parse it as a date.
35127      if (iso.charAt(0) === '"' && iso.charAt(iso.length - 1) === '"') {
35128        iso = iso.substring(1, iso.length - 1);
35129      }
35130      if (ISO_DATE_REGEXP.test(iso)) {
35131        return new Date(iso);
35132      }
35133      regexp.lastIndex = 0;
35134      parts = regexp.exec(iso);
35135
35136      if (parts) {
35137        parts.shift();
35138        if (date) {
35139          map = {
35140            yyyy: date.getFullYear(),
35141            MM: date.getMonth() + 1,
35142            dd: date.getDate(),
35143            HH: date.getHours(),
35144            mm: date.getMinutes(),
35145            ss: date.getSeconds(),
35146            sss: date.getMilliseconds() / 1000
35147          };
35148        } else {
35149          map = { yyyy: 1970, MM: 1, dd: 1, HH: 0, mm: 0, ss: 0, sss: 0 };
35150        }
35151
35152        forEach(parts, function(part, index) {
35153          if (index < mapping.length) {
35154            map[mapping[index]] = +part;
35155          }
35156        });
35157        return new Date(map.yyyy, map.MM - 1, map.dd, map.HH, map.mm, map.ss || 0, map.sss * 1000 || 0);
35158      }
35159    }
35160
35161    return NaN;
35162  };
35163}
35164
35165function createDateInputType(type, regexp, parseDate, format) {
35166  return function dynamicDateInputType(scope, element, attr, ctrl, $sniffer, $browser, $filter) {
35167    badInputChecker(scope, element, attr, ctrl);
35168    baseInputType(scope, element, attr, ctrl, $sniffer, $browser);
35169    var timezone = ctrl && ctrl.$options.getOption('timezone');
35170    var previousDate;
35171
35172    ctrl.$$parserName = type;
35173    ctrl.$parsers.push(function(value) {
35174      if (ctrl.$isEmpty(value)) return null;
35175      if (regexp.test(value)) {
35176        // Note: We cannot read ctrl.$modelValue, as there might be a different
35177        // parser/formatter in the processing chain so that the model
35178        // contains some different data format!
35179        var parsedDate = parseDate(value, previousDate);
35180        if (timezone) {
35181          parsedDate = convertTimezoneToLocal(parsedDate, timezone);
35182        }
35183        return parsedDate;
35184      }
35185      return undefined;
35186    });
35187
35188    ctrl.$formatters.push(function(value) {
35189      if (value && !isDate(value)) {
35190        throw ngModelMinErr('datefmt', 'Expected `{0}` to be a date', value);
35191      }
35192      if (isValidDate(value)) {
35193        previousDate = value;
35194        if (previousDate && timezone) {
35195          previousDate = convertTimezoneToLocal(previousDate, timezone, true);
35196        }
35197        return $filter('date')(value, format, timezone);
35198      } else {
35199        previousDate = null;
35200        return '';
35201      }
35202    });
35203
35204    if (isDefined(attr.min) || attr.ngMin) {
35205      var minVal;
35206      ctrl.$validators.min = function(value) {
35207        return !isValidDate(value) || isUndefined(minVal) || parseDate(value) >= minVal;
35208      };
35209      attr.$observe('min', function(val) {
35210        minVal = parseObservedDateValue(val);
35211        ctrl.$validate();
35212      });
35213    }
35214
35215    if (isDefined(attr.max) || attr.ngMax) {
35216      var maxVal;
35217      ctrl.$validators.max = function(value) {
35218        return !isValidDate(value) || isUndefined(maxVal) || parseDate(value) <= maxVal;
35219      };
35220      attr.$observe('max', function(val) {
35221        maxVal = parseObservedDateValue(val);
35222        ctrl.$validate();
35223      });
35224    }
35225
35226    function isValidDate(value) {
35227      // Invalid Date: getTime() returns NaN
35228      return value && !(value.getTime && value.getTime() !== value.getTime());
35229    }
35230
35231    function parseObservedDateValue(val) {
35232      return isDefined(val) && !isDate(val) ? parseDate(val) || undefined : val;
35233    }
35234  };
35235}
35236
35237function badInputChecker(scope, element, attr, ctrl) {
35238  var node = element[0];
35239  var nativeValidation = ctrl.$$hasNativeValidators = isObject(node.validity);
35240  if (nativeValidation) {
35241    ctrl.$parsers.push(function(value) {
35242      var validity = element.prop(VALIDITY_STATE_PROPERTY) || {};
35243      return validity.badInput || validity.typeMismatch ? undefined : value;
35244    });
35245  }
35246}
35247
35248function numberFormatterParser(ctrl) {
35249  ctrl.$$parserName = 'number';
35250  ctrl.$parsers.push(function(value) {
35251    if (ctrl.$isEmpty(value))      return null;
35252    if (NUMBER_REGEXP.test(value)) return parseFloat(value);
35253    return undefined;
35254  });
35255
35256  ctrl.$formatters.push(function(value) {
35257    if (!ctrl.$isEmpty(value)) {
35258      if (!isNumber(value)) {
35259        throw ngModelMinErr('numfmt', 'Expected `{0}` to be a number', value);
35260      }
35261      value = value.toString();
35262    }
35263    return value;
35264  });
35265}
35266
35267function parseNumberAttrVal(val) {
35268  if (isDefined(val) && !isNumber(val)) {
35269    val = parseFloat(val);
35270  }
35271  return !isNumberNaN(val) ? val : undefined;
35272}
35273
35274function isNumberInteger(num) {
35275  // See http://stackoverflow.com/questions/14636536/how-to-check-if-a-variable-is-an-integer-in-javascript#14794066
35276  // (minus the assumption that `num` is a number)
35277
35278  // eslint-disable-next-line no-bitwise
35279  return (num | 0) === num;
35280}
35281
35282function countDecimals(num) {
35283  var numString = num.toString();
35284  var decimalSymbolIndex = numString.indexOf('.');
35285
35286  if (decimalSymbolIndex === -1) {
35287    if (-1 < num && num < 1) {
35288      // It may be in the exponential notation format (`1e-X`)
35289      var match = /e-(\d+)$/.exec(numString);
35290
35291      if (match) {
35292        return Number(match[1]);
35293      }
35294    }
35295
35296    return 0;
35297  }
35298
35299  return numString.length - decimalSymbolIndex - 1;
35300}
35301
35302function isValidForStep(viewValue, stepBase, step) {
35303  // At this point `stepBase` and `step` are expected to be non-NaN values
35304  // and `viewValue` is expected to be a valid stringified number.
35305  var value = Number(viewValue);
35306
35307  var isNonIntegerValue = !isNumberInteger(value);
35308  var isNonIntegerStepBase = !isNumberInteger(stepBase);
35309  var isNonIntegerStep = !isNumberInteger(step);
35310
35311  // Due to limitations in Floating Point Arithmetic (e.g. `0.3 - 0.2 !== 0.1` or
35312  // `0.5 % 0.1 !== 0`), we need to convert all numbers to integers.
35313  if (isNonIntegerValue || isNonIntegerStepBase || isNonIntegerStep) {
35314    var valueDecimals = isNonIntegerValue ? countDecimals(value) : 0;
35315    var stepBaseDecimals = isNonIntegerStepBase ? countDecimals(stepBase) : 0;
35316    var stepDecimals = isNonIntegerStep ? countDecimals(step) : 0;
35317
35318    var decimalCount = Math.max(valueDecimals, stepBaseDecimals, stepDecimals);
35319    var multiplier = Math.pow(10, decimalCount);
35320
35321    value = value * multiplier;
35322    stepBase = stepBase * multiplier;
35323    step = step * multiplier;
35324
35325    if (isNonIntegerValue) value = Math.round(value);
35326    if (isNonIntegerStepBase) stepBase = Math.round(stepBase);
35327    if (isNonIntegerStep) step = Math.round(step);
35328  }
35329
35330  return (value - stepBase) % step === 0;
35331}
35332
35333function numberInputType(scope, element, attr, ctrl, $sniffer, $browser) {
35334  badInputChecker(scope, element, attr, ctrl);
35335  numberFormatterParser(ctrl);
35336  baseInputType(scope, element, attr, ctrl, $sniffer, $browser);
35337
35338  var minVal;
35339  var maxVal;
35340
35341  if (isDefined(attr.min) || attr.ngMin) {
35342    ctrl.$validators.min = function(value) {
35343      return ctrl.$isEmpty(value) || isUndefined(minVal) || value >= minVal;
35344    };
35345
35346    attr.$observe('min', function(val) {
35347      minVal = parseNumberAttrVal(val);
35348      // TODO(matsko): implement validateLater to reduce number of validations
35349      ctrl.$validate();
35350    });
35351  }
35352
35353  if (isDefined(attr.max) || attr.ngMax) {
35354    ctrl.$validators.max = function(value) {
35355      return ctrl.$isEmpty(value) || isUndefined(maxVal) || value <= maxVal;
35356    };
35357
35358    attr.$observe('max', function(val) {
35359      maxVal = parseNumberAttrVal(val);
35360      // TODO(matsko): implement validateLater to reduce number of validations
35361      ctrl.$validate();
35362    });
35363  }
35364
35365  if (isDefined(attr.step) || attr.ngStep) {
35366    var stepVal;
35367    ctrl.$validators.step = function(modelValue, viewValue) {
35368      return ctrl.$isEmpty(viewValue) || isUndefined(stepVal) ||
35369             isValidForStep(viewValue, minVal || 0, stepVal);
35370    };
35371
35372    attr.$observe('step', function(val) {
35373      stepVal = parseNumberAttrVal(val);
35374      // TODO(matsko): implement validateLater to reduce number of validations
35375      ctrl.$validate();
35376    });
35377  }
35378}
35379
35380function rangeInputType(scope, element, attr, ctrl, $sniffer, $browser) {
35381  badInputChecker(scope, element, attr, ctrl);
35382  numberFormatterParser(ctrl);
35383  baseInputType(scope, element, attr, ctrl, $sniffer, $browser);
35384
35385  var supportsRange = ctrl.$$hasNativeValidators && element[0].type === 'range',
35386      minVal = supportsRange ? 0 : undefined,
35387      maxVal = supportsRange ? 100 : undefined,
35388      stepVal = supportsRange ? 1 : undefined,
35389      validity = element[0].validity,
35390      hasMinAttr = isDefined(attr.min),
35391      hasMaxAttr = isDefined(attr.max),
35392      hasStepAttr = isDefined(attr.step);
35393
35394  var originalRender = ctrl.$render;
35395
35396  ctrl.$render = supportsRange && isDefined(validity.rangeUnderflow) && isDefined(validity.rangeOverflow) ?
35397    //Browsers that implement range will set these values automatically, but reading the adjusted values after
35398    //$render would cause the min / max validators to be applied with the wrong value
35399    function rangeRender() {
35400      originalRender();
35401      ctrl.$setViewValue(element.val());
35402    } :
35403    originalRender;
35404
35405  if (hasMinAttr) {
35406    ctrl.$validators.min = supportsRange ?
35407      // Since all browsers set the input to a valid value, we don't need to check validity
35408      function noopMinValidator() { return true; } :
35409      // non-support browsers validate the min val
35410      function minValidator(modelValue, viewValue) {
35411        return ctrl.$isEmpty(viewValue) || isUndefined(minVal) || viewValue >= minVal;
35412      };
35413
35414    setInitialValueAndObserver('min', minChange);
35415  }
35416
35417  if (hasMaxAttr) {
35418    ctrl.$validators.max = supportsRange ?
35419      // Since all browsers set the input to a valid value, we don't need to check validity
35420      function noopMaxValidator() { return true; } :
35421      // non-support browsers validate the max val
35422      function maxValidator(modelValue, viewValue) {
35423        return ctrl.$isEmpty(viewValue) || isUndefined(maxVal) || viewValue <= maxVal;
35424      };
35425
35426    setInitialValueAndObserver('max', maxChange);
35427  }
35428
35429  if (hasStepAttr) {
35430    ctrl.$validators.step = supportsRange ?
35431      function nativeStepValidator() {
35432        // Currently, only FF implements the spec on step change correctly (i.e. adjusting the
35433        // input element value to a valid value). It's possible that other browsers set the stepMismatch
35434        // validity error instead, so we can at least report an error in that case.
35435        return !validity.stepMismatch;
35436      } :
35437      // ngStep doesn't set the setp attr, so the browser doesn't adjust the input value as setting step would
35438      function stepValidator(modelValue, viewValue) {
35439        return ctrl.$isEmpty(viewValue) || isUndefined(stepVal) ||
35440               isValidForStep(viewValue, minVal || 0, stepVal);
35441      };
35442
35443    setInitialValueAndObserver('step', stepChange);
35444  }
35445
35446  function setInitialValueAndObserver(htmlAttrName, changeFn) {
35447    // interpolated attributes set the attribute value only after a digest, but we need the
35448    // attribute value when the input is first rendered, so that the browser can adjust the
35449    // input value based on the min/max value
35450    element.attr(htmlAttrName, attr[htmlAttrName]);
35451    attr.$observe(htmlAttrName, changeFn);
35452  }
35453
35454  function minChange(val) {
35455    minVal = parseNumberAttrVal(val);
35456    // ignore changes before model is initialized
35457    if (isNumberNaN(ctrl.$modelValue)) {
35458      return;
35459    }
35460
35461    if (supportsRange) {
35462      var elVal = element.val();
35463      // IE11 doesn't set the el val correctly if the minVal is greater than the element value
35464      if (minVal > elVal) {
35465        elVal = minVal;
35466        element.val(elVal);
35467      }
35468      ctrl.$setViewValue(elVal);
35469    } else {
35470      // TODO(matsko): implement validateLater to reduce number of validations
35471      ctrl.$validate();
35472    }
35473  }
35474
35475  function maxChange(val) {
35476    maxVal = parseNumberAttrVal(val);
35477    // ignore changes before model is initialized
35478    if (isNumberNaN(ctrl.$modelValue)) {
35479      return;
35480    }
35481
35482    if (supportsRange) {
35483      var elVal = element.val();
35484      // IE11 doesn't set the el val correctly if the maxVal is less than the element value
35485      if (maxVal < elVal) {
35486        element.val(maxVal);
35487        // IE11 and Chrome don't set the value to the minVal when max < min
35488        elVal = maxVal < minVal ? minVal : maxVal;
35489      }
35490      ctrl.$setViewValue(elVal);
35491    } else {
35492      // TODO(matsko): implement validateLater to reduce number of validations
35493      ctrl.$validate();
35494    }
35495  }
35496
35497  function stepChange(val) {
35498    stepVal = parseNumberAttrVal(val);
35499    // ignore changes before model is initialized
35500    if (isNumberNaN(ctrl.$modelValue)) {
35501      return;
35502    }
35503
35504    // Some browsers don't adjust the input value correctly, but set the stepMismatch error
35505    if (supportsRange && ctrl.$viewValue !== element.val()) {
35506      ctrl.$setViewValue(element.val());
35507    } else {
35508      // TODO(matsko): implement validateLater to reduce number of validations
35509      ctrl.$validate();
35510    }
35511  }
35512}
35513
35514function urlInputType(scope, element, attr, ctrl, $sniffer, $browser) {
35515  // Note: no badInputChecker here by purpose as `url` is only a validation
35516  // in browsers, i.e. we can always read out input.value even if it is not valid!
35517  baseInputType(scope, element, attr, ctrl, $sniffer, $browser);
35518  stringBasedInputType(ctrl);
35519
35520  ctrl.$$parserName = 'url';
35521  ctrl.$validators.url = function(modelValue, viewValue) {
35522    var value = modelValue || viewValue;
35523    return ctrl.$isEmpty(value) || URL_REGEXP.test(value);
35524  };
35525}
35526
35527function emailInputType(scope, element, attr, ctrl, $sniffer, $browser) {
35528  // Note: no badInputChecker here by purpose as `url` is only a validation
35529  // in browsers, i.e. we can always read out input.value even if it is not valid!
35530  baseInputType(scope, element, attr, ctrl, $sniffer, $browser);
35531  stringBasedInputType(ctrl);
35532
35533  ctrl.$$parserName = 'email';
35534  ctrl.$validators.email = function(modelValue, viewValue) {
35535    var value = modelValue || viewValue;
35536    return ctrl.$isEmpty(value) || EMAIL_REGEXP.test(value);
35537  };
35538}
35539
35540function radioInputType(scope, element, attr, ctrl) {
35541  var doTrim = !attr.ngTrim || trim(attr.ngTrim) !== 'false';
35542  // make the name unique, if not defined
35543  if (isUndefined(attr.name)) {
35544    element.attr('name', nextUid());
35545  }
35546
35547  var listener = function(ev) {
35548    var value;
35549    if (element[0].checked) {
35550      value = attr.value;
35551      if (doTrim) {
35552        value = trim(value);
35553      }
35554      ctrl.$setViewValue(value, ev && ev.type);
35555    }
35556  };
35557
35558  element.on('click', listener);
35559
35560  ctrl.$render = function() {
35561    var value = attr.value;
35562    if (doTrim) {
35563      value = trim(value);
35564    }
35565    element[0].checked = (value === ctrl.$viewValue);
35566  };
35567
35568  attr.$observe('value', ctrl.$render);
35569}
35570
35571function parseConstantExpr($parse, context, name, expression, fallback) {
35572  var parseFn;
35573  if (isDefined(expression)) {
35574    parseFn = $parse(expression);
35575    if (!parseFn.constant) {
35576      throw ngModelMinErr('constexpr', 'Expected constant expression for `{0}`, but saw ' +
35577                                   '`{1}`.', name, expression);
35578    }
35579    return parseFn(context);
35580  }
35581  return fallback;
35582}
35583
35584function checkboxInputType(scope, element, attr, ctrl, $sniffer, $browser, $filter, $parse) {
35585  var trueValue = parseConstantExpr($parse, scope, 'ngTrueValue', attr.ngTrueValue, true);
35586  var falseValue = parseConstantExpr($parse, scope, 'ngFalseValue', attr.ngFalseValue, false);
35587
35588  var listener = function(ev) {
35589    ctrl.$setViewValue(element[0].checked, ev && ev.type);
35590  };
35591
35592  element.on('click', listener);
35593
35594  ctrl.$render = function() {
35595    element[0].checked = ctrl.$viewValue;
35596  };
35597
35598  // Override the standard `$isEmpty` because the $viewValue of an empty checkbox is always set to `false`
35599  // This is because of the parser below, which compares the `$modelValue` with `trueValue` to convert
35600  // it to a boolean.
35601  ctrl.$isEmpty = function(value) {
35602    return value === false;
35603  };
35604
35605  ctrl.$formatters.push(function(value) {
35606    return equals(value, trueValue);
35607  });
35608
35609  ctrl.$parsers.push(function(value) {
35610    return value ? trueValue : falseValue;
35611  });
35612}
35613
35614
35615/**
35616 * @ngdoc directive
35617 * @name textarea
35618 * @restrict E
35619 *
35620 * @description
35621 * HTML textarea element control with angular data-binding. The data-binding and validation
35622 * properties of this element are exactly the same as those of the
35623 * {@link ng.directive:input input element}.
35624 *
35625 * @param {string} ngModel Assignable angular expression to data-bind to.
35626 * @param {string=} name Property name of the form under which the control is published.
35627 * @param {string=} required Sets `required` validation error key if the value is not entered.
35628 * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
35629 *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
35630 *    `required` when you want to data-bind to the `required` attribute.
35631 * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
35632 *    minlength.
35633 * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
35634 *    maxlength. Setting the attribute to a negative or non-numeric value, allows view values of any
35635 *    length.
35636 * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel {@link ngModel.NgModelController#$viewValue $viewValue}
35637 *    does not match a RegExp found by evaluating the Angular expression given in the attribute value.
35638 *    If the expression evaluates to a RegExp object, then this is used directly.
35639 *    If the expression evaluates to a string, then it will be converted to a RegExp
35640 *    after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to
35641 *    `new RegExp('^abc$')`.<br />
35642 *    **Note:** Avoid using the `g` flag on the RegExp, as it will cause each successive search to
35643 *    start at the index of the last search's match, thus not taking the whole input value into
35644 *    account.
35645 * @param {string=} ngChange Angular expression to be executed when input changes due to user
35646 *    interaction with the input element.
35647 * @param {boolean=} [ngTrim=true] If set to false Angular will not automatically trim the input.
35648 *
35649 * @knownIssue
35650 *
35651 * When specifying the `placeholder` attribute of `<textarea>`, Internet Explorer will temporarily
35652 * insert the placeholder value as the textarea's content. If the placeholder value contains
35653 * interpolation (`{{ ... }}`), an error will be logged in the console when Angular tries to update
35654 * the value of the by-then-removed text node. This doesn't affect the functionality of the
35655 * textarea, but can be undesirable.
35656 *
35657 * You can work around this Internet Explorer issue by using `ng-attr-placeholder` instead of
35658 * `placeholder` on textareas, whenever you need interpolation in the placeholder value. You can
35659 * find more details on `ngAttr` in the
35660 * [Interpolation](guide/interpolation#-ngattr-for-binding-to-arbitrary-attributes) section of the
35661 * Developer Guide.
35662 */
35663
35664
35665/**
35666 * @ngdoc directive
35667 * @name input
35668 * @restrict E
35669 *
35670 * @description
35671 * HTML input element control. When used together with {@link ngModel `ngModel`}, it provides data-binding,
35672 * input state control, and validation.
35673 * Input control follows HTML5 input types and polyfills the HTML5 validation behavior for older browsers.
35674 *
35675 * <div class="alert alert-warning">
35676 * **Note:** Not every feature offered is available for all input types.
35677 * Specifically, data binding and event handling via `ng-model` is unsupported for `input[file]`.
35678 * </div>
35679 *
35680 * @param {string} ngModel Assignable angular expression to data-bind to.
35681 * @param {string=} name Property name of the form under which the control is published.
35682 * @param {string=} required Sets `required` validation error key if the value is not entered.
35683 * @param {boolean=} ngRequired Sets `required` attribute if set to true
35684 * @param {number=} ngMinlength Sets `minlength` validation error key if the value is shorter than
35685 *    minlength.
35686 * @param {number=} ngMaxlength Sets `maxlength` validation error key if the value is longer than
35687 *    maxlength. Setting the attribute to a negative or non-numeric value, allows view values of any
35688 *    length.
35689 * @param {string=} ngPattern Sets `pattern` validation error key if the ngModel {@link ngModel.NgModelController#$viewValue $viewValue}
35690 *    value does not match a RegExp found by evaluating the Angular expression given in the attribute value.
35691 *    If the expression evaluates to a RegExp object, then this is used directly.
35692 *    If the expression evaluates to a string, then it will be converted to a RegExp
35693 *    after wrapping it in `^` and `$` characters. For instance, `"abc"` will be converted to
35694 *    `new RegExp('^abc$')`.<br />
35695 *    **Note:** Avoid using the `g` flag on the RegExp, as it will cause each successive search to
35696 *    start at the index of the last search's match, thus not taking the whole input value into
35697 *    account.
35698 * @param {string=} ngChange Angular expression to be executed when input changes due to user
35699 *    interaction with the input element.
35700 * @param {boolean=} [ngTrim=true] If set to false Angular
vendor: 4,842 bytes, lines 35700-35818
35700 will not automatically trim the input.
35701 *    This parameter is ignored for input[type=password] controls, which will never trim the
35702 *    input.
35703 *
35704 * @example
35705    <example name="input-directive" module="inputExample">
35706      <file name="index.html">
35707       <script>
35708          angular.module('inputExample', [])
35709            .controller('ExampleController', ['$scope', function($scope) {
35710              $scope.user = {name: 'guest', last: 'visitor'};
35711            }]);
35712       </script>
35713       <div ng-controller="ExampleController">
35714         <form name="myForm">
35715           <label>
35716              User name:
35717              <input type="text" name="userName" ng-model="user.name" required>
35718           </label>
35719           <div role="alert">
35720             <span class="error" ng-show="myForm.userName.$error.required">
35721              Required!</span>
35722           </div>
35723           <label>
35724              Last name:
35725              <input type="text" name="lastName" ng-model="user.last"
35726              ng-minlength="3" ng-maxlength="10">
35727           </label>
35728           <div role="alert">
35729             <span class="error" ng-show="myForm.lastName.$error.minlength">
35730               Too short!</span>
35731             <span class="error" ng-show="myForm.lastName.$error.maxlength">
35732               Too long!</span>
35733           </div>
35734         </form>
35735         <hr>
35736         <tt>user = {{user}}</tt><br/>
35737         <tt>myForm.userName.$valid = {{myForm.userName.$valid}}</tt><br/>
35738         <tt>myForm.userName.$error = {{myForm.userName.$error}}</tt><br/>
35739         <tt>myForm.lastName.$valid = {{myForm.lastName.$valid}}</tt><br/>
35740         <tt>myForm.lastName.$error = {{myForm.lastName.$error}}</tt><br/>
35741         <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
35742         <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
35743         <tt>myForm.$error.minlength = {{!!myForm.$error.minlength}}</tt><br/>
35744         <tt>myForm.$error.maxlength = {{!!myForm.$error.maxlength}}</tt><br/>
35745       </div>
35746      </file>
35747      <file name="protractor.js" type="protractor">
35748        var user = element(by.exactBinding('user'));
35749        var userNameValid = element(by.binding('myForm.userName.$valid'));
35750        var lastNameValid = element(by.binding('myForm.lastName.$valid'));
35751        var lastNameError = element(by.binding('myForm.lastName.$error'));
35752        var formValid = element(by.binding('myForm.$valid'));
35753        var userNameInput = element(by.model('user.name'));
35754        var userLastInput = element(by.model('user.last'));
35755
35756        it('should initialize to model', function() {
35757          expect(user.getText()).toContain('{"name":"guest","last":"visitor"}');
35758          expect(userNameValid.getText()).toContain('true');
35759          expect(formValid.getText()).toContain('true');
35760        });
35761
35762        it('should be invalid if empty when required', function() {
35763          userNameInput.clear();
35764          userNameInput.sendKeys('');
35765
35766          expect(user.getText()).toContain('{"last":"visitor"}');
35767          expect(userNameValid.getText()).toContain('false');
35768          expect(formValid.getText()).toContain('false');
35769        });
35770
35771        it('should be valid if empty when min length is set', function() {
35772          userLastInput.clear();
35773          userLastInput.sendKeys('');
35774
35775          expect(user.getText()).toContain('{"name":"guest","last":""}');
35776          expect(lastNameValid.getText()).toContain('true');
35777          expect(formValid.getText()).toContain('true');
35778        });
35779
35780        it('should be invalid if less than required min length', function() {
35781          userLastInput.clear();
35782          userLastInput.sendKeys('xx');
35783
35784          expect(user.getText()).toContain('{"name":"guest"}');
35785          expect(lastNameValid.getText()).toContain('false');
35786          expect(lastNameError.getText()).toContain('minlength');
35787          expect(formValid.getText()).toContain('false');
35788        });
35789
35790        it('should be invalid if longer than max length', function() {
35791          userLastInput.clear();
35792          userLastInput.sendKeys('some ridiculously long name');
35793
35794          expect(user.getText()).toContain('{"name":"guest"}');
35795          expect(lastNameValid.getText()).toContain('false');
35796          expect(lastNameError.getText()).toContain('maxlength');
35797          expect(formValid.getText()).toContain('false');
35798        });
35799      </file>
35800    </example>
35801 */
35802var inputDirective = ['$browser', '$sniffer', '$filter', '$parse',
35803    function($browser, $sniffer, $filter, $parse) {
35804  return {
35805    restrict: 'E',
35806    require: ['?ngModel'],
35807    link: {
35808      pre: function(scope, element, attr, ctrls) {
35809        if (ctrls[0]) {
35810          (inputType[lowercase(attr.type)] || inputType.text)(scope, element, attr, ctrls[0], $sniffer,
35811                                                              $browser, $filter, $parse);
35812        }
35813      }
35814    }
35815  };
35816}];
35817
35818
35819
35820var CONSTANT_VALUE_REGEXP = /^(true|false|\d+)$/;
35821/**
35822 * @ngdoc directive
35823 * @name ngValue
35824 *
35825 * @description
35826 * Binds the given expression to the value of the element.
35827 *
35828 * It is mainly used on {@link input[radio] `input[radio]`} and option elements,
35829 * so that when the element is selected, the {@link ngModel `ngModel`} of that element (or its
35830 * {@link select `select`} parent element) is set to the bound value. It is especially useful
35831 * for dynamically generated lists using {@link ngRepeat `ngRepeat`}, as shown below.
35832 *
35833 * It can also be used to achieve one-way binding of a given expression to an input element
35834 * such as an `input[text]` or a `textarea`, when that element does not use ngModel.
35835 *
35836 * @element input
35837 * @param {string=} ngValue angular expression, whose value will be bound to the `value` attribute
35838 * and `value` property of the element.
35839 *
35840 * @example
35841    <example name="ngValue-directive" module="valueExample">
35842      <file name="index.html">
35843       <script>
35844          angular.module('valueExample', [])
35845            .controller('ExampleController', ['$scope', function($scope) {
35846              $scope.names = ['pizza', 'unicorns', 'robots'];
35847              $scope.my = { favorite: 'unicorns' };
35848            }]);
35849       </script>
35850        <form ng-controller="ExampleController">
35851          <h2>Which is your favorite?</h2>
35852            <label ng-repeat="name in names" for="{{name}}">
35853              {{name}}
35854              <input type="radio"
35855                     ng-model="my.favorite"
35856                     ng-value="name"
35857                     id="{{name}}"
35858                     name="favorite">
35859            </label>
35860          <div>You chose {{my.favorite}}</div>
35861        </form>
35862      </file>
35863      <file name="protractor.js" type="protractor">
35864        var favorite = element(by.binding('my.favorite'));
35865
35866        it('should initialize to model', function() {
35867          expect(favorite.getText()).toContain('unicorns');
35868        });
35869        it('should bind the values to the inputs', function() {
35870          element.all(by.model('my.favorite')).get(0).click();
35871          expect(favorite.getText()).toContain('pizza');
35872        });
35873      </file>
35874    </example>
35875 */
35876var ngValueDirective = function() {
35877  /**
35878   *  inputs use the value attribute as their default value if the value property is not set.
35879   *  Once the value property has been set (by adding input), it will not react to changes to
35880   *  the value attribute anymore. Setting both attribute and property fixes this behavior, and
35881   *  makes it possible to use ngValue as a sort of one-way bind.
35882   */
35883  function updateElementValue(element, attr, value) {
35884    // Support: IE9 only
35885    // In IE9 values are converted to string (e.g. `input.value = null` results in `input.value === 'null'`).
35886    var propValue = isDefined(value) ? value : (msie === 9) ? '' : null;
35887    element.prop('value', propValue);
35888    attr.$set('value', value);
35889  }
35890
35891  return {
35892    restrict: 'A',
35893    priority: 100,
35894    compile: function(tpl, tplAttr) {
35895      if (CONSTANT_VALUE_REGEXP.test(tplAttr.ngValue)) {
35896        return function ngValueConstantLink(scope, elm, attr) {
35897          var value = scope.$eval(attr.ngValue);
35898          updateElementValue(elm, attr, value);
35899        };
35900      } else {
35901        return function ngValueLink(scope, elm, attr) {
35902          scope.$watch(attr.ngValue, function valueWatchAction(value) {
35903            updateElementValue(elm, attr, value);
35904          });
35905        };
35906      }
35907    }
35908  };
35909};
35910
35911/**
35912 * @ngdoc directive
35913 * @name ngBind
35914 * @restrict AC
35915 *
35916 * @description
35917 * The `ngBind` attribute tells Angular to replace the text content of the specified HTML element
35918 * with the value of a given expression, and to update the text content when the value of that
35919 * expression changes.
35920 *
35921 * Typically, you don't use `ngBind` directly, but instead you use the double curly markup like
35922 * `{{ expression }}` which is similar but less verbose.
35923 *
35924 * It is preferable to use `ngBind` instead of `{{ expression }}` if a template is momentarily
35925 * displayed by the browser in its raw state before Angular
vendor: 4,777 bytes, lines 35925-36055
35925 compiles it. Since `ngBind` is an
35926 * element attribute, it makes the bindings invisible to the user while the page is loading.
35927 *
35928 * An alternative solution to this problem would be using the
35929 * {@link ng.directive:ngCloak ngCloak} directive.
35930 *
35931 *
35932 * @element ANY
35933 * @param {expression} ngBind {@link guide/expression Expression} to evaluate.
35934 *
35935 * @example
35936 * Enter a name in the Live Preview text box; the greeting below the text box changes instantly.
35937   <example module="bindExample" name="ng-bind">
35938     <file name="index.html">
35939       <script>
35940         angular.module('bindExample', [])
35941           .controller('ExampleController', ['$scope', function($scope) {
35942             $scope.name = 'Whirled';
35943           }]);
35944       </script>
35945       <div ng-controller="ExampleController">
35946         <label>Enter name: <input type="text" ng-model="name"></label><br>
35947         Hello <span ng-bind="name"></span>!
35948       </div>
35949     </file>
35950     <file name="protractor.js" type="protractor">
35951       it('should check ng-bind', function() {
35952         var nameInput = element(by.model('name'));
35953
35954         expect(element(by.binding('name')).getText()).toBe('Whirled');
35955         nameInput.clear();
35956         nameInput.sendKeys('world');
35957         expect(element(by.binding('name')).getText()).toBe('world');
35958       });
35959     </file>
35960   </example>
35961 */
35962var ngBindDirective = ['$compile', function($compile) {
35963  return {
35964    restrict: 'AC',
35965    compile: function ngBindCompile(templateElement) {
35966      $compile.$$addBindingClass(templateElement);
35967      return function ngBindLink(scope, element, attr) {
35968        $compile.$$addBindingInfo(element, attr.ngBind);
35969        element = element[0];
35970        scope.$watch(attr.ngBind, function ngBindWatchAction(value) {
35971          element.textContent = stringify(value);
35972        });
35973      };
35974    }
35975  };
35976}];
35977
35978
35979/**
35980 * @ngdoc directive
35981 * @name ngBindTemplate
35982 *
35983 * @description
35984 * The `ngBindTemplate` directive specifies that the element
35985 * text content should be replaced with the interpolation of the template
35986 * in the `ngBindTemplate` attribute.
35987 * Unlike `ngBind`, the `ngBindTemplate` can contain multiple `{{` `}}`
35988 * expressions. This directive is needed since some HTML elements
35989 * (such as TITLE and OPTION) cannot contain SPAN elements.
35990 *
35991 * @element ANY
35992 * @param {string} ngBindTemplate template of form
35993 *   <tt>{{</tt> <tt>expression</tt> <tt>}}</tt> to eval.
35994 *
35995 * @example
35996 * Try it here: enter text in text box and watch the greeting change.
35997   <example module="bindExample" name="ng-bind-template">
35998     <file name="index.html">
35999       <script>
36000         angular.module('bindExample', [])
36001           .controller('ExampleController', ['$scope', function($scope) {
36002             $scope.salutation = 'Hello';
36003             $scope.name = 'World';
36004           }]);
36005       </script>
36006       <div ng-controller="ExampleController">
36007        <label>Salutation: <input type="text" ng-model="salutation"></label><br>
36008        <label>Name: <input type="text" ng-model="name"></label><br>
36009        <pre ng-bind-template="{{salutation}} {{name}}!"></pre>
36010       </div>
36011     </file>
36012     <file name="protractor.js" type="protractor">
36013       it('should check ng-bind', function() {
36014         var salutationElem = element(by.binding('salutation'));
36015         var salutationInput = element(by.model('salutation'));
36016         var nameInput = element(by.model('name'));
36017
36018         expect(salutationElem.getText()).toBe('Hello World!');
36019
36020         salutationInput.clear();
36021         salutationInput.sendKeys('Greetings');
36022         nameInput.clear();
36023         nameInput.sendKeys('user');
36024
36025         expect(salutationElem.getText()).toBe('Greetings user!');
36026       });
36027     </file>
36028   </example>
36029 */
36030var ngBindTemplateDirective = ['$interpolate', '$compile', function($interpolate, $compile) {
36031  return {
36032    compile: function ngBindTemplateCompile(templateElement) {
36033      $compile.$$addBindingClass(templateElement);
36034      return function ngBindTemplateLink(scope, element, attr) {
36035        var interpolateFn = $interpolate(element.attr(attr.$attr.ngBindTemplate));
36036        $compile.$$addBindingInfo(element, interpolateFn.expressions);
36037        element = element[0];
36038        attr.$observe('ngBindTemplate', function(value) {
36039          element.textContent = isUndefined(value) ? '' : value;
36040        });
36041      };
36042    }
36043  };
36044}];
36045
36046
36047/**
36048 * @ngdoc directive
36049 * @name ngBindHtml
36050 *
36051 * @description
36052 * Evaluates the expression and inserts the resulting HTML into the element in a secure way. By default,
36053 * the resulting HTML content will be sanitized using the {@link ngSanitize.$sanitize $sanitize} service.
36054 * To utilize this functionality, ensure that `$sanitize` is available, for example, by including {@link
36055 * ngSanitize} in your module's dependencies (not in core Angular
36055). In order to use {@link ngSanitize}
36056 * in your module's dependencies, you need to include "angular-sanitize.js" in your application.
36057 *
36058 * You may also bypass sanitization for values you know are safe. To do so, bind to
36059 * an explicitly trusted value via {@link ng.$sce#trustAsHtml $sce.trustAsHtml}.  See the example
36060 * under {@link ng.$sce#show-me-an-example-using-sce- Strict Contextual Escaping (SCE)}.
36061 *
36062 * Note: If a `$sanitize` service is unavailable and the bound value isn't explicitly trusted, you
36063 * will have an exception (instead of an exploit.)
36064 *
36065 * @element ANY
36066 * @param {expression} ngBindHtml {@link guide/expression Expression} to evaluate.
36067 *
36068 * @example
36069
36070   <example module="bindHtmlExample" deps="angular-sanitize.js" name="ng-bind-html">
36071     <file name="index.html">
36072       <div ng-controller="ExampleController">
36073        <p ng-bind-html="myHTML"></p>
36074       </div>
36075     </file>
36076
36077     <file name="script.js">
36078       angular.module('bindHtmlExample', ['ngSanitize'])
36079         .controller('ExampleController', ['$scope', function($scope) {
36080           $scope.myHTML =
36081              'I am an <code>HTML</code>string with ' +
36082              '<a href="#">links!</a> and other <em>stuff</em>';
36083         }]);
36084     </file>
36085
36086     <file name="protractor.js" type="protractor">
36087       it('should check ng-bind-html', function() {
36088         expect(element(by.binding('myHTML')).getText()).toBe(
36089             'I am an HTMLstring with links! and other stuff');
36090       });
36091     </file>
36092   </example>
36093 */
36094var ngBindHtmlDirective = ['$sce', '$parse', '$compile', function($sce, $parse, $compile) {
36095  return {
36096    restrict: 'A',
36097    compile: function ngBindHtmlCompile(tElement, tAttrs) {
36098      var ngBindHtmlGetter = $parse(tAttrs.ngBindHtml);
36099      var ngBindHtmlWatch = $parse(tAttrs.ngBindHtml, function sceValueOf(val) {
36100        // Unwrap the value to compare the actual inner safe value, not the wrapper object.
36101        return $sce.valueOf(val);
36102      });
36103      $compile.$$addBindingClass(tElement);
36104
36105      return function ngBindHtmlLink(scope, element, attr) {
36106        $compile.$$addBindingInfo(element, attr.ngBindHtml);
36107
36108        scope.$watch(ngBindHtmlWatch, function ngBindHtmlWatchAction() {
36109          // The watched value is the unwrapped value. To avoid re-escaping, use the direct getter.
36110          var value = ngBindHtmlGetter(scope);
36111          element.html($sce.getTrustedHtml(value) || '');
36112        });
36113      };
36114    }
36115  };
36116}];
36117
36118/**
36119 * @ngdoc directive
36120 * @name ngChange
36121 *
36122 * @description
36123 * Evaluate the given expression when the user changes the input.
36124 * The expression is evaluated immediately, unlike the JavaScript onchange event
36125 * which only triggers at the end of a change (usually, when the user leaves the
36126 * form element or presses the return key).
36127 *
36128 * The `ngChange` expression is only evaluated when a change in the input value causes
36129 * a new value to be committed to the model.
36130 *
36131 * It will not be evaluated:
36132 * * if the value returned from the `$parsers` transformation pipeline has not changed
36133 * * if the input has continued to be invalid since the model will stay `null`
36134 * * if the model is changed programmatically and not by a change to the input value
36135 *
36136 *
36137 * Note, this directive requires `ngModel` to be present.
36138 *
36139 * @element input
36140 * @param {expression} ngChange {@link guide/expression Expression} to evaluate upon change
36141 * in input value.
36142 *
36143 * @example
36144 * <example name="ngChange-directive" module="changeExample">
36145 *   <file name="index.html">
36146 *     <script>
36147 *       angular.module('changeExample', [])
36148 *         .controller('ExampleController', ['$scope', function($scope) {
36149 *           $scope.counter = 0;
36150 *           $scope.change = function() {
36151 *             $scope.counter++;
36152 *           };
36153 *         }]);
36154 *     </script>
36155 *     <div ng-controller="ExampleController">
36156 *       <input type="checkbox" ng-model="confirmed" ng-change="change()" id="ng-change-example1" />
36157 *       <input type="checkbox" ng-model="confirmed" id="ng-change-example2" />
36158 *       <label for="ng-change-example2">Confirmed</label><br />
36159 *       <tt>debug = {{confirmed}}</tt><br/>
36160 *       <tt>counter = {{counter}}</tt><br/>
36161 *     </div>
36162 *   </file>
36163 *   <file name="protractor.js" type="protractor">
36164 *     var counter = element(by.binding('counter'));
36165 *     var debug = element(by.binding('confirmed'));
36166 *
36167 *     it('should evaluate the expression if changing from view', function() {
36168 *       expect(counter.getText()).toContain('0');
36169 *
36170 *       element(by.id('ng-change-example1')).click();
36171 *
36172 *       expect(counter.getText()).toContain('1');
36173 *       expect(debug.getText()).toContain('true');
36174 *     });
36175 *
36176 *     it('should not evaluate the expression if changing from model', function() {
36177 *       element(by.id('ng-change-example2')).click();
36178
36179 *       expect(counter.getText()).toContain('0');
36180 *       expect(debug.getText()).toContain('true');
36181 *     });
36182 *   </file>
36183 * </example>
36184 */
36185var ngChangeDirective = valueFn({
36186  restrict: 'A',
36187  require: 'ngModel',
36188  link: function(scope, element, attr, ctrl) {
36189    ctrl.$viewChangeListeners.push(function() {
36190      scope.$eval(attr.ngChange);
36191    });
36192  }
36193});
36194
36195/* exported
36196  ngClassDirective,
36197  ngClassEvenDirective,
36198  ngClassOddDirective
36199*/
36200
36201function classDirective(name, selector) {
36202  name = 'ngClass' + name;
36203  var indexWatchExpression;
36204
36205  return ['$parse', function($parse) {
36206    return {
36207      restrict: 'AC',
36208      link: function(scope, element, attr) {
36209        var expression = attr[name].trim();
36210        var isOneTime = (expression.charAt(0) === ':') && (expression.charAt(1) === ':');
36211
36212        var watchInterceptor = isOneTime ? toFlatValue : toClassString;
36213        var watchExpression = $parse(expression, watchInterceptor);
36214        var watchAction = isOneTime ? ngClassOneTimeWatchAction : ngClassWatchAction;
36215
36216        var classCounts = element.data('$classCounts');
36217        var oldModulo = true;
36218        var oldClassString;
36219
36220        if (!classCounts) {
36221          // Use createMap() to prevent class assumptions involving property
36222          // names in Object.prototype
36223          classCounts = createMap();
36224          element.data('$classCounts', classCounts);
36225        }
36226
36227        if (name !== 'ngClass') {
36228          if (!indexWatchExpression) {
36229            indexWatchExpression = $parse('$index', function moduloTwo($index) {
36230              // eslint-disable-next-line no-bitwise
36231              return $index & 1;
36232            });
36233          }
36234
36235          scope.$watch(indexWatchExpression, ngClassIndexWatchAction);
36236        }
36237
36238        scope.$watch(watchExpression, watchAction, isOneTime);
36239
36240        function addClasses(classString) {
36241          classString = digestClassCounts(split(classString), 1);
36242          attr.$addClass(classString);
36243        }
36244
36245        function removeClasses(classString) {
36246          classString = digestClassCounts(split(classString), -1);
36247          attr.$removeClass(classString);
36248        }
36249
36250        function updateClasses(oldClassString, newClassString) {
36251          var oldClassArray = split(oldClassString);
36252          var newClassArray = split(newClassString);
36253
36254          var toRemoveArray = arrayDifference(oldClassArray, newClassArray);
36255          var toAddArray = arrayDifference(newClassArray, oldClassArray);
36256
36257          var toRemoveString = digestClassCounts(toRemoveArray, -1);
36258          var toAddString = digestClassCounts(toAddArray, 1);
36259
36260          attr.$addClass(toAddString);
36261          attr.$removeClass(toRemoveString);
36262        }
36263
36264        function digestClassCounts(classArray, count) {
36265          var classesToUpdate = [];
36266
36267          forEach(classArray, function(className) {
36268            if (count > 0 || classCounts[className]) {
36269              classCounts[className] = (classCounts[className] || 0) + count;
36270              if (classCounts[className] === +(count > 0)) {
36271                classesToUpdate.push(className);
36272              }
36273            }
36274          });
36275
36276          return classesToUpdate.join(' ');
36277        }
36278
36279        function ngClassIndexWatchAction(newModulo) {
36280          // This watch-action should run before the `ngClass[OneTime]WatchAction()`, thus it
36281          // adds/removes `oldClassString`. If the `ngClass` expression has changed as well, the
36282          // `ngClass[OneTime]WatchAction()` will update the classes.
36283          if (newModulo === selector) {
36284            addClasses(oldClassString);
36285          } else {
36286            removeClasses(oldClassString);
36287          }
36288
36289          oldModulo = newModulo;
36290        }
36291
36292        function ngClassOneTimeWatchAction(newClassValue) {
36293          var newClassString = toClassString(newClassValue);
36294
36295          if (newClassString !== oldClassString) {
36296            ngClassWatchAction(newClassString);
36297          }
36298        }
36299
36300        function ngClassWatchAction(newClassString) {
36301          if (oldModulo === selector) {
36302            updateClasses(oldClassString, newClassString);
36303          }
36304
36305          oldClassString = newClassString;
36306        }
36307      }
36308    };
36309  }];
36310
36311  // Helpers
36312  function arrayDifference(tokens1, tokens2) {
36313    if (!tokens1 || !tokens1.length) return [];
36314    if (!tokens2 || !tokens2.length) return tokens1;
36315
36316    var values = [];
36317
36318    outer:
36319    for (var i = 0; i < tokens1.length; i++) {
36320      var token = tokens1[i];
36321      for (var j = 0; j < tokens2.length; j++) {
36322        if (token === tokens2[j]) continue outer;
36323      }
36324      values.push(token);
36325    }
36326
36327    return values;
36328  }
36329
36330  function split(classString) {
36331    return classString && classString.split(' ');
36332  }
36333
36334  function toClassString(classValue) {
36335    var classString = classValue;
36336
36337    if (isArray(classValue)) {
36338      classString = classValue.map(toClassString).join(' ');
36339    } else if (isObject(classValue)) {
36340      classString = Object.keys(classValue).
36341        filter(function(key) { return classValue[key]; }).
36342        join(' ');
36343    }
36344
36345    return classString;
36346  }
36347
36348  function toFlatValue(classValue) {
36349    var flatValue = classValue;
36350
36351    if (isArray(classValue)) {
36352      flatValue = classValue.map(toFlatValue);
36353    } else if (isObject(classValue)) {
36354      var hasUndefined = false;
36355
36356      flatValue = Object.keys(classValue).filter(function(key) {
36357        var value = classValue[key];
36358
36359        if (!hasUndefined && isUndefined(value)) {
36360          hasUndefined = true;
36361        }
36362
36363        return value;
36364      });
36365
36366      if (hasUndefined) {
36367        // Prevent the `oneTimeLiteralWatchInterceptor` from unregistering
36368        // the watcher, by including at least one `undefined` value.
36369        flatValue.push(undefined);
36370      }
36371    }
36372
36373    return flatValue;
36374  }
36375}
36376
36377/**
36378 * @ngdoc directive
36379 * @name ngClass
36380 * @restrict AC
36381 *
36382 * @description
36383 * The `ngClass` directive allows you to dynamically set CSS classes on an HTML element by databinding
36384 * an expression that represents all classes to be added.
36385 *
36386 * The directive operates in three different ways, depending on which of three types the expression
36387 * evaluates to:
36388 *
36389 * 1. If the expression evaluates to a string, the string should be one or more space-delimited class
36390 * names.
36391 *
36392 * 2. If the expression evaluates to an object, then for each key-value pair of the
36393 * object with a truthy value the corresponding key is used as a class name.
36394 *
36395 * 3. If the expression evaluates to an array, each element of the array should either be a string as in
36396 * type 1 or an object as in type 2. This means that you can mix strings and objects together in an array
36397 * to give you more control over what CSS classes appear. See the code below for an example of this.
36398 *
36399 *
36400 * The directive won't add duplicate classes if a particular class was already set.
36401 *
36402 * When the expression changes, the previously added classes are removed and only then are the
36403 * new classes added.
36404 *
36405 * @knownIssue
36406 * You should not use {@link guide/interpolation interpolation} in the value of the `class`
36407 * attribute, when using the `ngClass` directive on the same element.
36408 * See {@link guide/interpolation#known-issues here} for more info.
36409 *
36410 * @animations
36411 * | Animation                        | Occurs                              |
36412 * |----------------------------------|-------------------------------------|
36413 * | {@link ng.$animate#addClass addClass}       | just before the class is applied to the element   |
36414 * | {@link ng.$animate#removeClass removeClass} | just before the class is removed from the element |
36415 *
36416 * @element ANY
36417 * @param {expression} ngClass {@link guide/expression Expression} to eval. The result
36418 *   of the evaluation can be a string representing space delimited class
36419 *   names, an array, or a map of class names to boolean values. In the case of a map, the
36420 *   names of the properties whose values are truthy will be added as css classes to the
36421 *   element.
36422 *
36423 * @example Example that demonstrates basic bindings via ngClass directive.
36424   <example name="ng-class">
36425     <file name="index.html">
36426       <p ng-class="{strike: deleted, bold: important, 'has-error': error}">Map Syntax Example</p>
36427       <label>
36428          <input type="checkbox" ng-model="deleted">
36429          deleted (apply "strike" class)
36430       </label><br>
36431       <label>
36432          <input type="checkbox" ng-model="important">
36433          important (apply "bold" class)
36434       </label><br>
36435       <label>
36436          <input type="checkbox" ng-model="error">
36437          error (apply "has-error" class)
36438       </label>
36439       <hr>
36440       <p ng-class="style">Using String Syntax</p>
36441       <input type="text" ng-model="style"
36442              placeholder="Type: bold strike red" aria-label="Type: bold strike red">
36443       <hr>
36444       <p ng-class="[style1, style2, style3]">Using Array Syntax</p>
36445       <input ng-model="style1"
36446              placeholder="Type: bold, strike or red" aria-label="Type: bold, strike or red"><br>
36447       <input ng-model="style2"
36448              placeholder="Type: bold, strike or red" aria-label="Type: bold, strike or red 2"><br>
36449       <input ng-model="style3"
36450              placeholder="Type: bold, strike or red" aria-label="Type: bold, strike or red 3"><br>
36451       <hr>
36452       <p ng-class="[style4, {orange: warning}]">Using Array and Map Syntax</p>
36453       <input ng-model="style4" placeholder="Type: bold, strike" aria-label="Type: bold, strike"><br>
36454       <label><input type="checkbox" ng-model="warning"> warning (apply "orange" class)</label>
36455     </file>
36456     <file name="style.css">
36457       .strike {
36458           text-decoration: line-through;
36459       }
36460       .bold {
36461           font-weight: bold;
36462       }
36463       .red {
36464           color: red;
36465       }
36466       .has-error {
36467           color: red;
36468           background-color: yellow;
36469       }
36470       .orange {
36471           color: orange;
36472       }
36473     </file>
36474     <file name="protractor.js" type="protractor">
36475       var ps = element.all(by.css('p'));
36476
36477       it('should let you toggle the class', function() {
36478
36479         expect(ps.first().getAttribute('class')).not.toMatch(/bold/);
36480         expect(ps.first().getAttribute('class')).not.toMatch(/has-error/);
36481
36482         element(by.model('important')).click();
36483         expect(ps.first().getAttribute('class')).toMatch(/bold/);
36484
36485         element(by.model('error')).click();
36486         expect(ps.first().getAttribute('class')).toMatch(/has-error/);
36487       });
36488
36489       it('should let you toggle string example', function() {
36490         expect(ps.get(1).getAttribute('class')).toBe('');
36491         element(by.model('style')).clear();
36492         element(by.model('style')).sendKeys('red');
36493         expect(ps.get(1).getAttribute('class')).toBe('red');
36494       });
36495
36496       it('array example should have 3 classes', function() {
36497         expect(ps.get(2).getAttribute('class')).toBe('');
36498         element(by.model('style1')).sendKeys('bold');
36499         element(by.model('style2')).sendKeys('strike');
36500         element(by.model('style3')).sendKeys('red');
36501         expect(ps.get(2).getAttribute('class')).toBe('bold strike red');
36502       });
36503
36504       it('array with map example should have 2 classes', function() {
36505         expect(ps.last().getAttribute('class')).toBe('');
36506         element(by.model('style4')).sendKeys('bold');
36507         element(by.model('warning')).click();
36508         expect(ps.last().getAttribute('class')).toBe('bold orange');
36509       });
36510     </file>
36511   </example>
36512
36513   ## Animations
36514
36515   The example below demonstrates how to perform animations using ngClass.
36516
36517   <example module="ngAnimate" deps="angular-animate.js" animations="true" name="ng-class">
36518     <file name="index.html">
36519      <input id="setbtn" type="button" value="set" ng-click="myVar='my-class'">
36520      <input id="clearbtn" type="button" value="clear" ng-click="myVar=''">
36521      <br>
36522      <span class="base-class" ng-class="myVar">Sample Text</span>
36523     </file>
36524     <file name="style.css">
36525       .base-class {
36526         transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
36527       }
36528
36529       .base-class.my-class {
36530         color: red;
36531         font-size:3em;
36532       }
36533     </file>
36534     <file name="protractor.js" type="protractor">
36535       it('should check ng-class', function() {
36536         expect(element(by.css('.base-class')).getAttribute('class')).not.
36537           toMatch(/my-class/);
36538
36539         element(by.id('setbtn')).click();
36540
36541         expect(element(by.css('.base-class')).getAttribute('class')).
36542           toMatch(/my-class/);
36543
36544         element(by.id('clearbtn')).click();
36545
36546         expect(element(by.css('.base-class')).getAttribute('class')).not.
36547           toMatch(/my-class/);
36548       });
36549     </file>
36550   </example>
36551
36552
36553   ## ngClass and pre-existing CSS3 Transitions/Animations
36554   The ngClass directive still supports CSS3 Transitions/Animations even if they do not follow the ngAnimate CSS naming structure.
36555   Upon animation ngAnimate will apply supplementary CSS classes to track the start and end of an animation, but this will not hinder
36556   any pre-existing CSS transitions already on the element. To get an idea of what happens during a class-based animation, be sure
36557   to view the step by step details of {@link $animate#addClass $animate.addClass} and
36558   {@link $animate#removeClass $animate.removeClass}.
36559 */
36560var ngClassDirective = classDirective('', true);
36561
36562/**
36563 * @ngdoc directive
36564 * @name ngClassOdd
36565 * @restrict AC
36566 *
36567 * @description
36568 * The `ngClassOdd` and `ngClassEven` directives work exactly as
36569 * {@link ng.directive:ngClass ngClass}, except they work in
36570 * conjunction with `ngRepeat` and take effect only on odd (even) rows.
36571 *
36572 * This directive can be applied only within the scope of an
36573 * {@link ng.directive:ngRepeat ngRepeat}.
36574 *
36575 * @element ANY
36576 * @param {expression} ngClassOdd {@link guide/expression Expression} to eval. The result
36577 *   of the evaluation can be a string representing space delimited class names or an array.
36578 *
36579 * @example
36580   <example name="ng-class-odd">
36581     <file name="index.html">
36582        <ol ng-init="names=['John', 'Mary', 'Cate', 'Suz']">
36583          <li ng-repeat="name in names">
36584           <span ng-class-odd="'odd'" ng-class-even="'even'">
36585             {{name}}
36586           </span>
36587          </li>
36588        </ol>
36589     </file>
36590     <file name="style.css">
36591       .odd {
36592         color: red;
36593       }
36594       .even {
36595         color: blue;
36596       }
36597     </file>
36598     <file name="protractor.js" type="protractor">
36599       it('should check ng-class-odd and ng-class-even', function() {
36600         expect(element(by.repeater('name in names').row(0).column('name')).getAttribute('class')).
36601           toMatch(/odd/);
36602         expect(element(by.repeater('name in names').row(1).column('name')).getAttribute('class')).
36603           toMatch(/even/);
36604       });
36605     </file>
36606   </example>
36607 */
36608var ngClassOddDirective = classDirective('Odd', 0);
36609
36610/**
36611 * @ngdoc directive
36612 * @name ngClassEven
36613 * @restrict AC
36614 *
36615 * @description
36616 * The `ngClassOdd` and `ngClassEven` directives work exactly as
36617 * {@link ng.directive:ngClass ngClass}, except they work in
36618 * conjunction with `ngRepeat` and take effect only on odd (even) rows.
36619 *
36620 * This directive can be applied only within the scope of an
36621 * {@link ng.directive:ngRepeat ngRepeat}.
36622 *
36623 * @element ANY
36624 * @param {expression} ngClassEven {@link guide/expression Expression} to eval. The
36625 *   result of the evaluation can be a string representing space delimited class names or an array.
36626 *
36627 * @example
36628   <example name="ng-class-even">
36629     <file name="index.html">
36630        <ol ng-init="names=['John', 'Mary', 'Cate', 'Suz']">
36631          <li ng-repeat="name in names">
36632           <span ng-class-odd="'odd'" ng-class-even="'even'">
36633             {{name}} &nbsp; &nbsp; &nbsp;
36634           </span>
36635          </li>
36636        </ol>
36637     </file>
36638     <file name="style.css">
36639       .odd {
36640         color: red;
36641       }
36642       .even {
36643         color: blue;
36644       }
36645     </file>
36646     <file name="protractor.js" type="protractor">
36647       it('should check ng-class-odd and ng-class-even', function() {
36648         expect(element(by.repeater('name in names').row(0).column('name')).getAttribute('class')).
36649           toMatch(/odd/);
36650         expect(element(by.repeater('name in names').row(1).column('name')).getAttribute('class')).
36651           toMatch(/even/);
36652       });
36653     </file>
36654   </example>
36655 */
36656var ngClassEvenDirective = classDirective('Even', 1);
36657
36658/**
36659 * @ngdoc directive
36660 * @name ngCloak
36661 * @restrict AC
36662 *
36663 * @description
36664 * The `ngCloak` directive is used to prevent the Angular html template from being briefly
36665 * displayed by the browser in its raw (uncompiled) form while your application is loading. Use this
36666 * directive to avoid the undesirable flicker effect caused by the html template display.
36667 *
36668 * The directive can be applied to the `<body>` element, but the preferred usage is to apply
36669 * multiple `ngCloak` directives to small portions of the page to permit progressive rendering
36670 * of the browser view.
36671 *
36672 * `ngCloak` works in cooperation with the following css rule embedded within `angular.js` and
36673 * `angular.min.js`.
36674 * For CSP mode please add `angular-csp.css` to your html file (see {@link ng.directive:ngCsp ngCsp}).
36675 *
36676 * ```css
36677 * [ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak {
36678 *   display: none !important;
36679 * }
36680 * ```
36681 *
36682 * When this css rule is loaded by the browser, all html elements (including their children) that
36683 * are tagged with the `ngCloak` directive are hidden. When Angular encounters this directive
36684 * during the compilation of the template it deletes the `ngCloak` element attribute, making
36685 * the compiled element visible.
36686 *
36687 * For the best result, the `angular.js` script must be loaded in the head section of the html
36688 * document; alternatively, the css rule above must be included in the external stylesheet of the
36689 * application.
36690 *
36691 * @element ANY
36692 *
36693 * @example
36694   <example name="ng-cloak">
36695     <file name="index.html">
36696        <div id="template1" ng-cloak>{{ 'hello' }}</div>
36697        <div id="template2" class="ng-cloak">{{ 'world' }}</div>
36698     </file>
36699     <file name="protractor.js" type="protractor">
36700       it('should remove the template directive and css class', function() {
36701         expect($('#template1').getAttribute('ng-cloak')).
36702           toBeNull();
36703         expect($('#template2').getAttribute('ng-cloak')).
36704           toBeNull();
36705       });
36706     </file>
36707   </example>
36708 *
36709 */
36710var ngCloakDirective = ngDirective({
36711  compile: function(element, attr) {
36712    attr.$set('ngCloak', undefined);
36713    element.removeClass('ng-cloak');
36714  }
36715});
36716
36717/**
36718 * @ngdoc directive
36719 * @name ngController
36720 *
36721 * @description
36722 * The `ngController` directive attaches a controller class to the view. This is a key aspect of how angular
36723 * supports the principles behind the Model-View-Controller design pattern.
36724 *
36725 * MVC components in angular:
36726 *
36727 * * Model — Models are the properties of a scope; scopes are attached to the DOM where scope properties
36728 *   are accessed through bindings.
36729 * * View — The template (HTML with data bindings) that is rendered into the View.
36730 * * Controller — The `ngController` directive specifies a Controller class; the class contains business
36731 *   logic behind the application to decorate the scope with functions and values
36732 *
36733 * Note that you can also attach controllers to the DOM by declaring it in a route definition
36734 * via the {@link ngRoute.$route $route} service. A common mistake is to declare the controller
36735 * again using `ng-controller` in the template itself.  This will cause the controller to be attached
36736 * and executed twice.
36737 *
36738 * @element ANY
36739 * @scope
36740 * @priority 500
36741 * @param {expression} ngController Name of a constructor function registered with the current
36742 * {@link ng.$controllerProvider $controllerProvider} or an {@link guide/expression expression}
36743 * that on the current scope evaluates to a constructor function.
36744 *
36745 * The controller instance can be published into a scope property by specifying
36746 * `ng-controller="as propertyName"`.
36747 *
36748 * If the current `$controllerProvider` is configured to use globals (via
36749 * {@link ng.$controllerProvider#allowGlobals `$controllerProvider.allowGlobals()` }), this may
36750 * also be the name of a globally accessible constructor function (deprecated, not recommended).
36751 *
36752 * @example
36753 * Here is a simple form for editing user contact information. Adding, remov
36753ing, clearing, and
36754 * greeting are methods declared on the controller (see source tab). These methods can
36755 * easily be called from the angular markup. Any changes to the data are automatically reflected
36756 * in the View without the need for a manual update.
36757 *
36758 * Two different declaration styles are included below:
36759 *
36760 * * one binds methods and properties directly onto the controller using `this`:
36761 * `ng-controller="SettingsController1 as settings"`
36762 * * one injects `$scope` into the controller:
36763 * `ng-controller="SettingsController2"`
36764 *
36765 * The second option is more common in the Angular community, and is generally used in boilerplates
36766 * and in this guide. However, there are advantages to binding properties directly to the controller
36767 * and avoiding scope.
36768 *
36769 * * Using `controller as` makes it obvious which controller you are accessing in the template when
36770 * multiple controllers apply to an element.
36771 * * If you are writing your controllers as classes you have easier access to the properties and
36772 * methods, which will appear on the scope, from inside the controller code.
36773 * * Since there is always a `.` in the bindings, you don't have to worry about prototypal
36774 * inheritance masking primitives.
36775 *
36776 * This example demonstrates the `controller as` syntax.
36777 *
36778 * <example name="ngControllerAs" module="controllerAsExample">
36779 *   <file name="index.html">
36780 *    <div id="ctrl-as-exmpl" ng-controller="SettingsController1 as settings">
36781 *      <label>Name: <input type="text" ng-model="settings.name"/></label>
36782 *      <button ng-click="settings.greet()">greet</button><br/>
36783 *      Contact:
36784 *      <ul>
36785 *        <li ng-repeat="contact in settings.contacts">
36786 *          <select ng-model="contact.type" aria-label="Contact method" id="select_{{$index}}">
36787 *             <option>phone</option>
36788 *             <option>email</option>
36789 *          </select>
36790 *          <input type="text" ng-model="contact.value" aria-labelledby="select_{{$index}}" />
36791 *          <button ng-click="settings.clearContact(contact)">clear</button>
36792 *          <button ng-click="settings.removeContact(contact)" aria-label="Remove">X</button>
36793 *        </li>
36794 *        <li><button ng-click="settings.addContact()">add</button></li>
36795 *     </ul>
36796 *    </div>
36797 *   </file>
36798 *   <file name="app.js">
36799 *    angular.module('controllerAsExample', [])
36800 *      .controller('SettingsController1', SettingsController1);
36801 *
36802 *    function SettingsController1() {
36803 *      this.name = 'John Smith';
36804 *      this.contacts = [
36805 *        {type: 'phone', value: '408 555 1212'},
36806 *        {type: 'email', value: '[email protected]'}
36807 *      ];
36808 *    }
36809 *
36810 *    SettingsController1.prototype.greet = function() {
36811 *      alert(this.name);
36812 *    };
36813 *
36814 *    SettingsController1.prototype.addContact = function() {
36815 *      this.contacts.push({type: 'email', value: '[email protected]'});
36816 *    };
36817 *
36818 *    SettingsController1.prototype.removeContact = function(contactToRemove) {
36819 *     var index = this.contacts.indexOf(contactToRemove);
36820 *      this.contacts.splice(index, 1);
36821 *    };
36822 *
36823 *    SettingsController1.prototype.clearContact = function(contact) {
36824 *      contact.type = 'phone';
36825 *      contact.value = '';
36826 *    };
36827 *   </file>
36828 *   <file name="protractor.js" type="protractor">
36829 *     it('should check controller as', function() {
36830 *       var container = element(by.id('ctrl-as-exmpl'));
36831 *         expect(container.element(by.model('settings.name'))
36832 *           .getAttribute('value')).toBe('John Smith');
36833 *
36834 *       var firstRepeat =
36835 *           container.element(by.repeater('contact in settings.contacts').row(0));
36836 *       var secondRepeat =
36837 *           container.element(by.repeater('contact in settings.contacts').row(1));
36838 *
36839 *       expect(firstRepeat.element(by.model('contact.value')).getAttribute('value'))
36840 *           .toBe('408 555 1212');
36841 *
36842 *       expect(secondRepeat.element(by.model('contact.value')).getAttribute('value'))
36843 *           .toBe('[email protected]');
36844 *
36845 *       firstRepeat.element(by.buttonText('clear')).click();
36846 *
36847 *       expect(firstRepeat.element(by.model('contact.value')).getAttribute('value'))
36848 *           .toBe('');
36849 *
36850 *       container.element(by.buttonText('add')).click();
36851 *
36852 *       expect(container.element(by.repeater('contact in settings.contacts').row(2))
36853 *           .element(by.model('contact.value'))
36854 *           .getAttribute('value'))
36855 *           .toBe('[email protected]');
36856 *     });
36857 *   </file>
36858 * </example>
36859 *
36860 * This example demonstrates the "attach to `$scope`" style of controller.
36861 *
36862 * <example name="ngController" module="controllerExample">
36863 *  <file name="index.html">
36864 *   <div id="ctrl-exmpl" ng-controller="SettingsController2">
36865 *     <label>Name: <input type="text" ng-model="name"/></label>
36866 *     <button ng-click="greet()">greet</button><br/>
36867 *     Contact:
36868 *     <ul>
36869 *       <li ng-repeat="contact in contacts">
36870 *         <select ng-model="contact.type" id="select_{{$index}}">
36871 *            <option>phone</option>
36872 *            <option>email</option>
36873 *         </select>
36874 *         <input type="text" ng-model="contact.value" aria-labelledby="select_{{$index}}" />
36875 *         <button ng-click="clearContact(contact)">clear</button>
36876 *         <button ng-click="removeContact(contact)">X</button>
36877 *       </li>
36878 *       <li>[ <button ng-click="addContact()">add</button> ]</li>
36879 *    </ul>
36880 *   </div>
36881 *  </file>
36882 *  <file name="app.js">
36883 *   angular.module('controllerExample', [])
36884 *     .controller('SettingsController2', ['$scope', SettingsController2]);
36885 *
36886 *   function SettingsController2($scope) {
36887 *     $scope.name = 'John Smith';
36888 *     $scope.contacts = [
36889 *       {type:'phone', value:'408 555 1212'},
36890 *       {type:'email', value:'[email protected]'}
36891 *     ];
36892 *
36893 *     $scope.greet = function() {
36894 *       alert($scope.name);
36895 *     };
36896 *
36897 *     $scope.addContact = function() {
36898 *       $scope.contacts.push({type:'email', value:'[email protected]'});
36899 *     };
36900 *
36901 *     $scope.removeContact = function(contactToRemove) {
36902 *       var index = $scope.contacts.indexOf(contactToRemove);
36903 *       $scope.contacts.splice(index, 1);
36904 *     };
36905 *
36906 *     $scope.clearContact = function(contact) {
36907 *       contact.type = 'phone';
36908 *       contact.value = '';
36909 *     };
36910 *   }
36911 *  </file>
36912 *  <file name="protractor.js" type="protractor">
36913 *    it('should check controller', function() {
36914 *      var container = element(by.id('ctrl-exmpl'));
36915 *
36916 *      expect(container.element(by.model('name'))
36917 *          .getAttribute('value')).toBe('John Smith');
36918 *
36919 *      var firstRepeat =
36920 *          container.element(by.repeater('contact in contacts').row(0));
36921 *      var secondRepeat =
36922 *          container.element(by.repeater('contact in contacts').row(1));
36923 *
36924 *      expect(firstRepeat.element(by.model('contact.value')).getAttribute('value'))
36925 *          .toBe('408 555 1212');
36926 *      expect(secondRepeat.element(by.model('contact.value')).getAttribute('value'))
36927 *          .toBe('[email protected]');
36928 *
36929 *      firstRepeat.element(by.buttonText('clear')).click();
36930 *
36931 *      expect(firstRepeat.element(by.model('contact.value')).getAttribute('value'))
36932 *          .toBe('');
36933 *
36934 *      container.element(by.buttonText('add')).click();
36935 *
36936 *      expect(container.element(by.repeater('contact in contacts').row(2))
36937 *          .element(by.model('contact.value'))
36938 *          .getAttribute('value'))
36939 *          .toBe('[email protected]');
36940 *    });
36941 *  </file>
36942 *</example>
36943
36944 */
36945var ngControllerDirective = [function() {
36946  return {
36947    restrict: 'A',
36948    scope: true,
36949    controller: '@',
36950    priority: 500
36951  };
36952}];
36953
36954/**
36955 * @ngdoc directive
36956 * @name ngCsp
36957 *
36958 * @restrict A
36959 * @element ANY
36960 * @description
36961 *
36962 * Angular has some features that can conflict with certain restrictions that are applied when using
36963 * [CSP (Content Security Policy)](https://developer.mozilla.org/en/Security/CSP) rules.
36964 *
36965 * If you intend to implement CSP with these rules then you must tell Angular not to use these
36966 * features.
36967 *
36968 * This is necessary when developing things like Google Chrome Extensions or Universal Windows Apps.
36969 *
36970 *
36971 * The following default rules in CSP affect Angular:
36972 *
36973 * * The use of `eval()`, `Function(string)` and similar functions to dynamically create and execute
36974 * code from strings is forbidden. Angular makes use of this in the {@link $parse} service to
36975 * provide a 30% increase in the speed of evaluating Angular expressions. (This CSP rule can be
36976 * disabled with the CSP keyword `unsafe-eval`, but it is generally not recommended as it would
36977 * weaken the protections offered by CSP.)
36978 *
36979 * * The use of inline resources, such as inline `<script>` and `<style>` elements, are forbidden.
36980 * This prevents apps from injecting custom styles directly into the document. Angular makes use of
36981 * this to include some CSS rules (e.g. {@link ngCloak} and {@link ngHide}). To make these
36982 * directives work when a CSP rule is blocking inline styles, you must link to the `angular-csp.css`
36983 * in your HTML manually. (This CSP rule can be disabled with the CSP keyword `unsafe-inline`, but
36984 * it is generally not recommended as it would weaken the protections offered by CSP.)
36985 *
36986 * If you do not provide `ngCsp` then Angular tries to autodetect if CSP is blocking dynamic code
36987 * creation from strings (e.g., `unsafe-eval` not specified in CSP header) and automatically
36988 * deactivates this feature in the {@link $parse} service. This autodetection, however, triggers a
36989 * CSP error to be logged in the console:
36990 *
36991 * ```
36992 * Refused to evaluate a string as JavaScript because 'unsafe-eval' is not an allowed source of
36993 * script in the following Content Security Policy directive: "default-src 'self'". Note that
36994 * 'script-src' was not explicitly set, so 'default-src' is used as a fallback.
36995 * ```
36996 *
36997 * This error is harmless but annoying. To prevent the error from showing up, put the `ngCsp`
36998 * directive on an element of the HTML document that appears before the `<script>` tag that loads
36999 * the `angular.js` file.
37000 *
37001 * *Note: This directive is only available in the `ng-csp` and `data-ng-csp` attribute form.*
37002 *
37003 * You can specify which of the CSP related Angular features should be deactivated by providing
37004 * a value for the `ng-csp` attribute. The options are as follows:
37005 *
37006 * * no-inline-style: this stops Angular from injecting CSS styles into the DOM
37007 *
37008 * * no-unsafe-eval: this stops Angular from optimizing $parse with unsafe eval of strings
37009 *
37010 * You can use these values in the following combinations:
37011 *
37012 *
37013 * * No declaration means that Angular will assume that you can do inline styles, but it will do
37014 * a runtime check for unsafe-eval. E.g. `<body>`. This is backwardly compatible with previous
37015 * versions of Angular.
37016 *
37017 * * A simple `ng-csp` (or `data-ng-csp`) attribute will tell Angular to deactivate both inline
37018 * styles and unsafe eval. E.g. `<body ng-csp>`. This is backwardly compatible with previous
37019 * versions of Angular.
37020 *
37021 * * Specifying only `no-unsafe-eval` tells Angular that we must not use eval, but that we can
37022 * inject inline styles. E.g. `<body ng-csp="no-unsafe-eval">`.
37023 *
37024 * * Specifying only `no-inline-style` tells Angular that we must not inject styles, but that we can
37025 * run eval - no automatic check for unsafe eval will occur. E.g. `<body ng-csp="no-inline-style">`
37026 *
37027 * * Specifying both `no-unsafe-eval` and `no-inline-style` tells Angular that we must not inject
37028 * styles nor use eval, which is the same as an empty: ng-csp.
37029 * E.g.`<body ng-csp="no-inline-style;no-unsafe-eval">`
37030 *
37031 * @example
37032 * This example shows how to apply the `ngCsp` directive to the `html` tag.
37033   ```html
37034     <!doctype html>
37035     <html ng-app ng-csp>
37036     ...
37037     ...
37038     </html>
37039   ```
37040  * @example
37041      <!-- Note: the `.csp` suffix in the example name triggers CSP mode in our http server! -->
37042      <example name="example.csp" module="cspExample" ng-csp="true">
37043        <file name="index.html">
37044          <div ng-controller="MainController as ctrl">
37045            <div>
37046              <button ng-click="ctrl.inc()" id="inc">Increment</button>
37047              <span id="counter">
37048                {{ctrl.counter}}
37049              </span>
37050            </div>
37051
37052            <div>
37053              <button ng-click="ctrl.evil()" id="evil">Evil</button>
37054              <span id="evilError">
37055                {{ctrl.evilError}}
37056              </span>
37057            </div>
37058          </div>
37059        </file>
37060        <file name="script.js">
37061           angular.module('cspExample', [])
37062             .controller('MainController', function MainController() {
37063                this.counter = 0;
37064                this.inc = function() {
37065                  this.counter++;
37066                };
37067                this.evil = function() {
37068                  try {
37069                    eval('1+2'); // eslint-disable-line no-eval
37070                  } catch (e) {
37071                    this.evilError = e.message;
37072                  }
37073                };
37074              });
37075        </file>
37076        <file name="protractor.js" type="protractor">
37077          var util, webdriver;
37078
37079          var incBtn = element(by.id('inc'));
37080          var counter = element(by.id('counter'));
37081          var evilBtn = element(by.id('evil'));
37082          var evilError = element(by.id('evilError'));
37083
37084          function getAndClearSevereErrors() {
37085            return browser.manage().logs().get('browser').then(function(browserLog) {
37086              return browserLog.filter(function(logEntry) {
37087                return logEntry.level.value > webdriver.logging.Level.WARNING.value;
37088              });
37089            });
37090          }
37091
37092          function clearErrors() {
37093            getAndClearSevereErrors();
37094          }
37095
37096          function expectNoErrors() {
37097            getAndClearSevereErrors().then(function(filteredLog) {
37098              expect(filteredLog.length).toEqual(0);
37099              if (filteredLog.length) {
37100                console.log('browser console errors: ' + util.inspect(filteredLog));
37101              }
37102            });
37103          }
37104
37105          function expectError(regex) {
37106            getAndClearSevereErrors().then(function(filteredLog) {
37107              var found = false;
37108              filteredLog.forEach(function(log) {
37109                if (log.message.match(regex)) {
37110                  found = true;
37111                }
37112              });
37113              if (!found) {
37114                throw new Error('expected an error that matches ' + regex);
37115              }
37116            });
37117          }
37118
37119          beforeEach(function() {
37120            util = require('util');
37121            webdriver = require('selenium-webdriver');
37122          });
37123
37124          // For now, we only test on Chrome,
37125          // as Safari does not load the page with Protractor's injected scripts,
37126          // and Firefox webdriver always disables content security policy (#6358)
37127          if (browser.params.browser !== 'chrome') {
37128            return;
37129          }
37130
37131          it('should not report errors when the page is loaded', function() {
37132            // clear errors so we are not dependent on previous tests
37133            clearErrors();
37134            // Need to reload the page as the page is already loaded when
37135            // we come here
37136            browser.driver.getCurrentUrl().then(function(url) {
37137              browser.get(url);
37138            });
37139            expectNoErrors();
37140          });
37141
37142          it('should evaluate expressions', function() {
37143            expect(counter.getText()).toEqual('0');
37144            incBtn.click();
37145            expect(counter.getText()).toEqual('1');
37146            expectNoErrors();
37147          });
37148
37149          it('should throw and report an error when using "eval"', function() {
37150            evilBtn.click();
37151            expect(evilError.getText()).toMatch(/Content Security Policy/);
37152            expectError(/Content Security Policy/);
37153          });
37154        </file>
37155      </example>
37156  */
37157
37158// `ngCsp` is not implemented as a proper directive any more, because we need it be processed while
37159// we bootstrap the app (before `$parse` is instantiated). For this reason, we just have the `csp()`
37160// fn that looks for the `ng-csp` attribute anywhere in the current doc.
37161
37162/**
37163 * @ngdoc directive
37164 * @name ngClick
37165 *
37166 * @description
37167 * The ngClick directive allows you to specify custom behavior when
37168 * an element is clicked.
37169 *
37170 * @element ANY
37171 * @priority 0
37172 * @param {expression} ngClick {@link guide/expression Expression} to evaluate upon
37173 * click. ({@link guide/expression#-event- Event object is available as `$event`})
37174 *
37175 * @example
37176   <example name="ng-click">
37177     <file name="index.html">
37178      <button ng-click="count = count + 1" ng-init="count=0">
37179        Increment
37180      </button>
37181      <span>
37182        count: {{count}}
37183      </span>
37184     </file>
37185     <file name="protractor.js" type="protractor">
37186       it('should check ng-click', function() {
37187         expect(element(by.binding('count')).getText()).toMatch('0');
37188         element(by.css('button')).click();
37189         expect(element(by.binding('count')).getText()).toMatch('1');
37190       });
37191     </file>
37192   </example>
37193 */
37194/*
37195 * A collection of directives that allows creation of custom event handlers that are defined as
37196 * angular expressions and are compiled and executed within the current scope.
37197 */
37198var ngEventDirectives = {};
37199
37200// For events that might fire synchronously during DOM manipulation
37201// we need to execute their event handlers asynchronously using $evalAsync,
37202// so that they are not executed in an inconsistent state.
37203var forceAsyncEvents = {
37204  'blur': true,
37205  'focus': true
37206};
37207forEach(
37208  'click dblclick mousedown mouseup mouseover mouseout mousemove mouseenter mouseleave keydown keyup keypress submit focus blur copy cut paste'.split(' '),
37209  function(eventName) {
37210    var directiveName = directiveNormalize('ng-' + eventName);
37211    ngEventDirectives[directiveName] = ['$parse', '$rootScope', function($parse, $rootScope) {
37212      return {
37213        restrict: 'A',
37214        compile: function($element, attr) {
37215          // NOTE:
37216          // We expose the powerful `$event` object on the scope that provides access to the Window,
37217          // etc. This is OK, because expressions are not sandboxed any more (and the expression
37218          // sandbox was never meant to be a security feature anyway).
37219          var fn = $parse(attr[directiveName]);
37220          return function ngEventHandler(scope, element) {
37221            element.on(eventName, function(event) {
37222              var callback = function() {
37223                fn(scope, {$event: event});
37224              };
37225              if (forceAsyncEvents[eventName] && $rootScope.$$phase) {
37226                scope.$evalAsync(callback);
37227              } else {
37228                scope.$apply(callback);
37229              }
37230            });
37231          };
37232        }
37233      };
37234    }];
37235  }
37236);
37237
37238/**
37239 * @ngdoc directive
37240 * @name ngDblclick
37241 *
37242 * @description
37243 * The `ngDblclick` directive allows you to specify custom behavior on a dblclick event.
37244 *
37245 * @element ANY
37246 * @priority 0
37247 * @param {expression} ngDblclick {@link guide/expression Expression} to evaluate upon
37248 * a dblclick. (The Event object is available as `$event`)
37249 *
37250 * @example
37251   <example name="ng-dblclick">
37252     <file name="index.html">
37253      <button ng-dblclick="count = count + 1" ng-init="count=0">
37254        Increment (on double click)
37255      </button>
37256      count: {{count}}
37257     </file>
37258   </example>
37259 */
37260
37261
37262/**
37263 * @ngdoc directive
37264 * @name ngMousedown
37265 *
37266 * @description
37267 * The ngMousedown directive allows you to specify custom behavior on mousedown event.
37268 *
37269 * @element ANY
37270 * @priority 0
37271 * @param {expression} ngMousedown {@link guide/expression Expression} to evaluate upon
37272 * mousedown. ({@link guide/expression#-event- Event object is available as `$event`})
37273 *
37274 * @example
37275   <example name="ng-mousedown">
37276     <file name="index.html">
37277      <button ng-mousedown="count = count + 1" ng-init="count=0">
37278        Increment (on mouse down)
37279      </button>
37280      count: {{count}}
37281     </file>
37282   </example>
37283 */
37284
37285
37286/**
37287 * @ngdoc directive
37288 * @name ngMouseup
37289 *
37290 * @description
37291 * Specify custom behavior on mouseup event.
37292 *
37293 * @element ANY
37294 * @priority 0
37295 * @param {expression} ngMouseup {@link guide/expression Expression} to evaluate upon
37296 * mouseup. ({@link guide/expression#-event- Event object is available as `$event`})
37297 *
37298 * @example
37299   <example name="ng-mouseup">
37300     <file name="index.html">
37301      <button ng-mouseup="count = count + 1" ng-init="count=0">
37302        Increment (on mouse up)
37303      </button>
37304      count: {{count}}
37305     </file>
37306   </example>
37307 */
37308
37309/**
37310 * @ngdoc directive
37311 * @name ngMouseover
37312 *
37313 * @description
37314 * Specify custom behavior on mouseover event.
37315 *
37316 * @element ANY
37317 * @priority 0
37318 * @param {expression} ngMouseover {@link guide/expression Expression} to evaluate upon
37319 * mouseover. ({@link guide/expression#-event- Event object is available as `$event`})
37320 *
37321 * @example
37322   <example name="ng-mouseover">
37323     <file name="index.html">
37324      <button ng-mouseover="count = count + 1" ng-init="count=0">
37325        Increment (when mouse is over)
37326      </button>
37327      count: {{count}}
37328     </file>
37329   </example>
37330 */
37331
37332
37333/**
37334 * @ngdoc directive
37335 * @name ngMouseenter
37336 *
37337 * @description
37338 * Specify custom behavior on mouseenter event.
37339 *
37340 * @element ANY
37341 * @priority 0
37342 * @param {expression} ngMouseenter {@link guide/expression Expression} to evaluate upon
37343 * mouseenter. ({@link guide/expression#-event- Event object is available as `$event`})
37344 *
37345 * @example
37346   <example name="ng-mouseenter">
37347     <file name="index.html">
37348      <button ng-mouseenter="count = count + 1" ng-init="count=0">
37349        Increment (when mouse enters)
37350      </button>
37351      count: {{count}}
37352     </file>
37353   </example>
37354 */
37355
37356
37357/**
37358 * @ngdoc directive
37359 * @name ngMouseleave
37360 *
37361 * @description
37362 * Specify custom behavior on mouseleave event.
37363 *
37364 * @element ANY
37365 * @priority 0
37366 * @param {expression} ngMouseleave {@link guide/expression Expression} to evaluate upon
37367 * mouseleave. ({@link guide/expression#-event- Event object is available as `$event`})
37368 *
37369 * @example
37370   <example name="ng-mouseleave">
37371     <file name="index.html">
37372      <button ng-mouseleave="count = count + 1" ng-init="count=0">
37373        Increment (when mouse leaves)
37374      </button>
37375      count: {{count}}
37376     </file>
37377   </example>
37378 */
37379
37380
37381/**
37382 * @ngdoc directive
37383 * @name ngMousemove
37384 *
37385 * @description
37386 * Specify custom behavior on mousemove event.
37387 *
37388 * @element ANY
37389 * @priority 0
37390 * @param {expression} ngMousemove {@link guide/expression Expression} to evaluate upon
37391 * mousemove. ({@link guide/expression#-event- Event object is available as `$event`})
37392 *
37393 * @example
37394   <example name="ng-mousemove">
37395     <file name="index.html">
37396      <button ng-mousemove="count = count + 1" ng-init="count=0">
37397        Increment (when mouse moves)
37398      </button>
37399      count: {{count}}
37400     </file>
37401   </example>
37402 */
37403
37404
37405/**
37406 * @ngdoc directive
37407 * @name ngKeydown
37408 *
37409 * @description
37410 * Specify custom behavior on keydown event.
37411 *
37412 * @element ANY
37413 * @priority 0
37414 * @param {expression} ngKeydown {@link guide/expression Expression} to evaluate upon
37415 * keydown. (Event object is available as `$event` and can be interrogated for keyCode, altKey, etc.)
37416 *
37417 * @example
37418   <example name="ng-keydown">
37419     <file name="index.html">
37420      <input ng-keydown="count = count + 1" ng-init="count=0">
37421      key down count: {{count}}
37422     </file>
37423   </example>
37424 */
37425
37426
37427/**
37428 * @ngdoc directive
37429 * @name ngKeyup
37430 *
37431 * @description
37432 * Specify custom behavior on keyup event.
37433 *
37434 * @element ANY
37435 * @priority 0
37436 * @param {expression} ngKeyup {@link guide/expression Expression} to evaluate upon
37437 * keyup. (Event object is available as `$event` and can be interrogated for keyCode, altKey, etc.)
37438 *
37439 * @example
37440   <example name="ng-keyup">
37441     <file name="index.html">
37442       <p>Typing in the input box below updates the key count</p>
37443       <input ng-keyup="count = count + 1" ng-init="count=0"> key up count: {{count}}
37444
37445       <p>Typing in the input box below updates the keycode</p>
37446       <input ng-keyup="event=$event">
37447       <p>event keyCode: {{ event.keyCode }}</p>
37448       <p>event altKey: {{ event.altKey }}</p>
37449     </file>
37450   </example>
37451 */
37452
37453
37454/**
37455 * @ngdoc directive
37456 * @name ngKeypress
37457 *
37458 * @description
37459 * Specify custom behavior on keypress event.
37460 *
37461 * @element ANY
37462 * @param {expression} ngKeypress {@link guide/expression Expression} to evaluate upon
37463 * keypress. ({@link guide/expression#-event- Event object is available as `$event`}
37464 * and can be interrogated for keyCode, altKey, etc.)
37465 *
37466 * @example
37467   <example name="ng-keypress">
37468     <file name="index.html">
37469      <input ng-keypress="count = count + 1" ng-init="count=0">
37470      key press count: {{count}}
37471     </file>
37472   </example>
37473 */
37474
37475
37476/**
37477 * @ngdoc directive
37478 * @name ngSubmit
37479 *
37480 * @description
37481 * Enables binding angular expressions to onsubmit events.
37482 *
37483 * Additionally it prevents the default action (which for form means 
37483sending the request to the
37484 * server and reloading the current page), but only if the form does not contain `action`,
37485 * `data-action`, or `x-action` attributes.
37486 *
37487 * <div class="alert alert-warning">
37488 * **Warning:** Be careful not to cause "double-submission" by using both the `ngClick` and
37489 * `ngSubmit` handlers together. See the
37490 * {@link form#submitting-a-form-and-preventing-the-default-action `form` directive documentation}
37491 * for a detailed discussion of when `ngSubmit` may be triggered.
37492 * </div>
37493 *
37494 * @element form
37495 * @priority 0
37496 * @param {expression} ngSubmit {@link guide/expression Expression} to eval.
37497 * ({@link guide/expression#-event- Event object is available as `$event`})
37498 *
37499 * @example
37500   <example module="submitExample" name="ng-submit">
37501     <file name="index.html">
37502      <script>
37503        angular.module('submitExample', [])
37504          .controller('ExampleController', ['$scope', function($scope) {
37505            $scope.list = [];
37506            $scope.text = 'hello';
37507            $scope.submit = function() {
37508              if ($scope.text) {
37509                $scope.list.push(this.text);
37510                $scope.text = '';
37511              }
37512            };
37513          }]);
37514      </script>
37515      <form ng-submit="submit()" ng-controller="ExampleController">
37516        Enter text and hit enter:
37517        <input type="text" ng-model="text" name="text" />
37518        <input type="submit" id="submit" value="Submit" />
37519        <pre>list={{list}}</pre>
37520      </form>
37521     </file>
37522     <file name="protractor.js" type="protractor">
37523       it('should check ng-submit', function() {
37524         expect(element(by.binding('list')).getText()).toBe('list=[]');
37525         element(by.css('#submit')).click();
37526         expect(element(by.binding('list')).getText()).toContain('hello');
37527         expect(element(by.model('text')).getAttribute('value')).toBe('');
37528       });
37529       it('should ignore empty strings', function() {
37530         expect(element(by.binding('list')).getText()).toBe('list=[]');
37531         element(by.css('#submit')).click();
37532         element(by.css('#submit')).click();
37533         expect(element(by.binding('list')).getText()).toContain('hello');
37534        });
37535     </file>
37536   </example>
37537 */
37538
37539/**
37540 * @ngdoc directive
37541 * @name ngFocus
37542 *
37543 * @description
37544 * Specify custom behavior on focus event.
37545 *
37546 * Note: As the `focus` event is executed synchronously when calling `input.focus()`
37547 * AngularJS executes the expression using `scope.$evalAsync` if the event is fired
37548 * during an `$apply` to ensure a consistent state.
37549 *
37550 * @element window, input, select, textarea, a
37551 * @priority 0
37552 * @param {expression} ngFocus {@link guide/expression Expression} to evaluate upon
37553 * focus. ({@link guide/expression#-event- Event object is available as `$event`})
37554 *
37555 * @example
37556 * See {@link ng.directive:ngClick ngClick}
37557 */
37558
37559/**
37560 * @ngdoc directive
37561 * @name ngBlur
37562 *
37563 * @description
37564 * Specify custom behavior on blur event.
37565 *
37566 * A [blur event](https://developer.mozilla.org/en-US/docs/Web/Events/blur) fires when
37567 * an element has lost focus.
37568 *
37569 * Note: As the `blur` event is executed synchronously also during DOM manipulations
37570 * (e.g. removing a focussed input),
37571 * AngularJS executes the expression using `scope.$evalAsync` if the event is fired
37572 * during an `$apply` to ensure a consistent state.
37573 *
37574 * @element window, input, select, textarea, a
37575 * @priority 0
37576 * @param {expression} ngBlur {@link guide/expression Expression} to evaluate upon
37577 * blur. ({@link guide/expression#-event- Event object is available as `$event`})
37578 *
37579 * @example
37580 * See {@link ng.directive:ngClick ngClick}
37581 */
37582
37583/**
37584 * @ngdoc directive
37585 * @name ngCopy
37586 *
37587 * @description
37588 * Specify custom behavior on copy event.
37589 *
37590 * @element window, input, select, textarea, a
37591 * @priority 0
37592 * @param {expression} ngCopy {@link guide/expression Expression} to evaluate upon
37593 * copy. ({@link guide/expression#-event- Event object is available as `$event`})
37594 *
37595 * @example
37596   <example name="ng-copy">
37597     <file name="index.html">
37598      <input ng-copy="copied=true" ng-init="copied=false; value='copy me'" ng-model="value">
37599      copied: {{copied}}
37600     </file>
37601   </example>
37602 */
37603
37604/**
37605 * @ngdoc directive
37606 * @name ngCut
37607 *
37608 * @description
37609 * Specify custom behavior on cut event.
37610 *
37611 * @element window, input, select, textarea, a
37612 * @priority 0
37613 * @param {expression} ngCut {@link guide/expression Expression} to evaluate upon
37614 * cut. ({@link guide/expression#-event- Event object is available as `$event`})
37615 *
37616 * @example
37617   <example name="ng-cut">
37618     <file name="index.html">
37619      <input ng-cut="cut=true" ng-init="cut=false; value='cut me'" ng-model="value">
37620      cut: {{cut}}
37621     </file>
37622   </example>
37623 */
37624
37625/**
37626 * @ngdoc directive
37627 * @name ngPaste
37628 *
37629 * @description
37630 * Specify custom behavior on paste event.
37631 *
37632 * @element window, input, select, textarea, a
37633 * @priority 0
37634 * @param {expression} ngPaste {@link guide/expression Expression} to evaluate upon
37635 * paste. ({@link guide/expression#-event- Event object is available as `$event`})
37636 *
37637 * @example
37638   <example name="ng-paste">
37639     <file name="index.html">
37640      <input ng-paste="paste=true" ng-init="paste=false" placeholder='paste here'>
37641      pasted: {{paste}}
37642     </file>
37643   </example>
37644 */
37645
37646/**
37647 * @ngdoc directive
37648 * @name ngIf
37649 * @restrict A
37650 * @multiElement
37651 *
37652 * @description
37653 * The `ngIf` directive removes or recreates a portion of the DOM tree based on an
37654 * {expression}. If the expression assigned to `ngIf` evaluates to a false
37655 * value then the element is removed from the DOM, otherwise a clone of the
37656 * element is reinserted into the DOM.
37657 *
37658 * `ngIf` differs from `ngShow` and `ngHide` in that `ngIf` completely removes and recreates the
37659 * element in the DOM rather than changing its visibility via the `display` css property.  A common
37660 * case when this difference is significant is when using css selectors that rely on an element's
37661 * position within the DOM, such as the `:first-child` or `:last-child` pseudo-classe
37661s.
37662 *
37663 * Note that when an element is removed using `ngIf` its scope is destroyed and a new scope
37664 * is created when the element is restored.  The scope created within `ngIf` inherits from
37665 * its parent scope using
37666 * [prototypal inheritance](https://github.com/angular/angular.js/wiki/Understanding-Scopes#javascript-prototypal-inheritance).
37667 * An important implication of this is if `ngModel` is used within `ngIf` to bind to
37668 * a javascript primitive defined in the parent scope. In this case any modifications made to the
37669 * variable within the child scope will override (hide) the value in the parent scope.
37670 *
37671 * Also, `ngIf` recreates elements using their compiled state. An example of this behavior
37672 * is if an element's class attribute is directly modified after it's compiled, using something like
37673 * jQuery's `.addClass()` method, and the element is later removed. When `ngIf` recreates the element
37674 * the added class will be lost because the original compiled state is used to regenerate the element.
37675 *
37676 * Additionally, you can provide animations via the `ngAnimate` module to animate the `enter`
37677 * and `leave` effects.
37678 *
37679 * @animations
37680 * | Animation                        | Occurs                               |
37681 * |----------------------------------|-------------------------------------|
37682 * | {@link ng.$animate#enter enter}  | just after the `ngIf` contents change and a new DOM element is created and injected into the `ngIf` container |
37683 * | {@link ng.$animate#leave leave}  | just before the `ngIf` contents are removed from the DOM |
37684 *
37685 * @element ANY
37686 * @scope
37687 * @priority 600
37688 * @param {expression} ngIf If the {@link guide/expression expression} is falsy then
37689 *     the element is removed from the DOM tree. If it is truthy a copy of the compiled
37690 *     element is added to the DOM tree.
37691 *
37692 * @example
37693  <example module="ngAnimate" deps="angular-animate.js" animations="true" name="ng-if">
37694    <file name="index.html">
37695      <label>Click me: <input type="checkbox" ng-model="checked" ng-init="checked=true" /></label><br/>
37696      Show when checked:
37697      <span ng-if="checked" class="animate-if">
37698        This is removed when the checkbox is unchecked.
37699      </span>
37700    </file>
37701    <file name="animations.css">
37702      .animate-if {
37703        background:white;
37704        border:1px solid black;
37705        padding:10px;
37706      }
37707
37708      .animate-if.ng-enter, .animate-if.ng-leave {
37709        transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
37710      }
37711
37712      .animate-if.ng-enter,
37713      .animate-if.ng-leave.ng-leave-active {
37714        opacity:0;
37715      }
37716
37717      .animate-if.ng-leave,
37718      .animate-if.ng-enter.ng-enter-active {
37719        opacity:1;
37720      }
37721    </file>
37722  </example>
37723 */
37724var ngIfDirective = ['$animate', '$compile', function($animate, $compile) {
37725  return {
37726    multiElement: true,
37727    transclude: 'element',
37728    priority: 600,
37729    terminal: true,
37730    restrict: 'A',
37731    $$tlb: true,
37732    link: function($scope, $element, $attr, ctrl, $transclude) {
37733        var block, childScope, previousElements;
37734        $scope.$watch($attr.ngIf, function ngIfWatchAction(value) {
37735
37736          if (value) {
37737            if (!childScope) {
37738              $transclude(function(clone, newScope) {
37739                childScope = newScope;
37740                clone[clone.length++] = $compile.$$createComment('end ngIf', $attr.ngIf);
37741                // Note: We only need the first/last node of the cloned nodes.
37742                // However, we need to keep the reference to the jqlite wrapper as it might be changed later
37743                // by a directive with templateUrl when its template arrives.
37744                block = {
37745                  clone: clone
37746                };
37747                $animate.enter(clone, $element.parent(), $element);
37748              });
37749            }
37750          } else {
37751            if (previousElements) {
37752              previousElements.remove();
37753              previousElements = null;
37754            }
37755            if (childScope) {
37756              childScope.$destroy();
37757              childScope = null;
37758            }
37759            if (block) {
37760              previousElements = getBlockNodes(block.clone);
37761              $animate.leave(previousElements).done(function(response) {
37762                if (response !== false) previousElements = null;
37763              });
37764              block = null;
37765            }
37766          }
37767        });
37768    }
37769  };
37770}];
37771
37772/**
37773 * @ngdoc directive
37774 * @name ngInclude
37775 * @restrict ECA
37776 *
37777 * @description
37778 * Fetches, compiles and includes an external HTML fragment.
37779 *
37780 * By default, the template URL is restricted to the same domain and protocol as the
37781 * application document. This is done by calling {@link $sce#getTrustedResourceUrl
37782 * $sce.getTrustedResourceUrl} on it. To load templates from other domains or protocols
37783 * you may either {@link ng.$sceDelegateProvider#resourceUrlWhitelist whitelist them} or
37784 * {@link $sce#trustAsResourceUrl wrap them} as trusted values. Refer to Angular's {@link
37785 * ng.$sce Strict Contextual Escaping}.
37786 *
37787 * In addition, the browser's
37788 * [Same Origin Policy](https://code.google.com/p/browsersec/wiki/Part2#Same-origin_policy_for_XMLHttpRequest)
37789 * and [Cross-Origin Resource Sharing (CORS)](http://www.w3.org/TR/cors/)
37790 * policy may further restrict whether the template is successfully loaded.
37791 * For example, `ngInclude` won't work for cross-domain requests on all browsers and for `file://`
37792 * access on some browsers.
37793 *
37794 * @animations
37795 * | Animation                        | Occurs                              |
37796 * |----------------------------------|-------------------------------------|
37797 * | {@link ng.$animate#enter enter}  | when the expression changes, on the new include |
37798 * | {@link ng.$animate#leave leave}  | when the expression changes, on the old include |
37799 *
37800 * The enter and leave animation occur concurrently.
37801 *
37802 * @scope
37803 * @priority 400
37804 *
37805 * @param {string} ngInclude|src angular
vendor: 9,710 bytes, lines 37805-38082
37805 expression evaluating to URL. If the source is a string constant,
37806 *                 make sure you wrap it in **single** quotes, e.g. `src="'myPartialTemplate.html'"`.
37807 * @param {string=} onload Expression to evaluate when a new partial is loaded.
37808 *                  <div class="alert alert-warning">
37809 *                  **Note:** When using onload on SVG elements in IE11, the browser will try to call
37810 *                  a function with the name on the window element, which will usually throw a
37811 *                  "function is undefined" error. To fix this, you can instead use `data-onload` or a
37812 *                  different form that {@link guide/directive#normalization matches} `onload`.
37813 *                  </div>
37814   *
37815 * @param {string=} autoscroll Whether `ngInclude` should call {@link ng.$anchorScroll
37816 *                  $anchorScroll} to scroll the viewport after the content is loaded.
37817 *
37818 *                  - If the attribute is not set, disable scrolling.
37819 *                  - If the attribute is set without value, enable scrolling.
37820 *                  - Otherwise enable scrolling only if the expression evaluates to truthy value.
37821 *
37822 * @example
37823  <example module="includeExample" deps="angular-animate.js" animations="true" name="ng-include">
37824    <file name="index.html">
37825     <div ng-controller="ExampleController">
37826       <select ng-model="template" ng-options="t.name for t in templates">
37827        <option value="">(blank)</option>
37828       </select>
37829       url of the template: <code>{{template.url}}</code>
37830       <hr/>
37831       <div class="slide-animate-container">
37832         <div class="slide-animate" ng-include="template.url"></div>
37833       </div>
37834     </div>
37835    </file>
37836    <file name="script.js">
37837      angular.module('includeExample', ['ngAnimate'])
37838        .controller('ExampleController', ['$scope', function($scope) {
37839          $scope.templates =
37840            [{ name: 'template1.html', url: 'template1.html'},
37841             { name: 'template2.html', url: 'template2.html'}];
37842          $scope.template = $scope.templates[0];
37843        }]);
37844     </file>
37845    <file name="template1.html">
37846      Content of template1.html
37847    </file>
37848    <file name="template2.html">
37849      Content of template2.html
37850    </file>
37851    <file name="animations.css">
37852      .slide-animate-container {
37853        position:relative;
37854        background:white;
37855        border:1px solid black;
37856        height:40px;
37857        overflow:hidden;
37858      }
37859
37860      .slide-animate {
37861        padding:10px;
37862      }
37863
37864      .slide-animate.ng-enter, .slide-animate.ng-leave {
37865        transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
37866
37867        position:absolute;
37868        top:0;
37869        left:0;
37870        right:0;
37871        bottom:0;
37872        display:block;
37873        padding:10px;
37874      }
37875
37876      .slide-animate.ng-enter {
37877        top:-50px;
37878      }
37879      .slide-animate.ng-enter.ng-enter-active {
37880        top:0;
37881      }
37882
37883      .slide-animate.ng-leave {
37884        top:0;
37885      }
37886      .slide-animate.ng-leave.ng-leave-active {
37887        top:50px;
37888      }
37889    </file>
37890    <file name="protractor.js" type="protractor">
37891      var templateSelect = element(by.model('template'));
37892      var includeElem = element(by.css('[ng-include]'));
37893
37894      it('should load template1.html', function() {
37895        expect(includeElem.getText()).toMatch(/Content of template1.html/);
37896      });
37897
37898      it('should load template2.html', function() {
37899        if (browser.params.browser === 'firefox') {
37900          // Firefox can't handle using selects
37901          // See https://github.com/angular/protractor/issues/480
37902          return;
37903        }
37904        templateSelect.click();
37905        templateSelect.all(by.css('option')).get(2).click();
37906        expect(includeElem.getText()).toMatch(/Content of template2.html/);
37907      });
37908
37909      it('should change to blank', function() {
37910        if (browser.params.browser === 'firefox') {
37911          // Firefox can't handle using selects
37912          return;
37913        }
37914        templateSelect.click();
37915        templateSelect.all(by.css('option')).get(0).click();
37916        expect(includeElem.isPresent()).toBe(false);
37917      });
37918    </file>
37919  </example>
37920 */
37921
37922
37923/**
37924 * @ngdoc event
37925 * @name ngInclude#$includeContentRequested
37926 * @eventType emit on the scope ngInclude was declared in
37927 * @description
37928 * Emitted every time the ngInclude content is requested.
37929 *
37930 * @param {Object} angularEvent Synthetic event object.
37931 * @param {String} src URL of content to load.
37932 */
37933
37934
37935/**
37936 * @ngdoc event
37937 * @name ngInclude#$includeContentLoaded
37938 * @eventType emit on the current ngInclude scope
37939 * @description
37940 * Emitted every time the ngInclude content is reloaded.
37941 *
37942 * @param {Object} angularEvent Synthetic event object.
37943 * @param {String} src URL of content to load.
37944 */
37945
37946
37947/**
37948 * @ngdoc event
37949 * @name ngInclude#$includeContentError
37950 * @eventType emit on the scope ngInclude was declared in
37951 * @description
37952 * Emitted when a template HTTP request yields an erroneous response (status < 200 || status > 299)
37953 *
37954 * @param {Object} angularEvent Synthetic event object.
37955 * @param {String} src URL of content to load.
37956 */
37957var ngIncludeDirective = ['$templateRequest', '$anchorScroll', '$animate',
37958                  function($templateRequest,   $anchorScroll,   $animate) {
37959  return {
37960    restrict: 'ECA',
37961    priority: 400,
37962    terminal: true,
37963    transclude: 'element',
37964    controller: angular.noop,
37965    compile: function(element, attr) {
37966      var srcExp = attr.ngInclude || attr.src,
37967          onloadExp = attr.onload || '',
37968          autoScrollExp = attr.autoscroll;
37969
37970      return function(scope, $element, $attr, ctrl, $transclude) {
37971        var changeCounter = 0,
37972            currentScope,
37973            previousElement,
37974            currentElement;
37975
37976        var cleanupLastIncludeContent = function() {
37977          if (previousElement) {
37978            previousElement.remove();
37979            previousElement = null;
37980          }
37981          if (currentScope) {
37982            currentScope.$destroy();
37983            currentScope = null;
37984          }
37985          if (currentElement) {
37986            $animate.leave(currentElement).done(function(response) {
37987              if (response !== false) previousElement = null;
37988            });
37989            previousElement = currentElement;
37990            currentElement = null;
37991          }
37992        };
37993
37994        scope.$watch(srcExp, function ngIncludeWatchAction(src) {
37995          var afterAnimation = function(response) {
37996            if (response !== false && isDefined(autoScrollExp) &&
37997              (!autoScrollExp || scope.$eval(autoScrollExp))) {
37998                $anchorScroll();
37999            }
38000          };
38001          var thisChangeId = ++changeCounter;
38002
38003          if (src) {
38004            //set the 2nd param to true to ignore the template request error so that the inner
38005            //contents and scope can be cleaned up.
38006            $templateRequest(src, true).then(function(response) {
38007              if (scope.$$destroyed) return;
38008
38009              if (thisChangeId !== changeCounter) return;
38010              var newScope = scope.$new();
38011              ctrl.template = response;
38012
38013              // Note: This will also link all children of ng-include that were contained in the original
38014              // html. If that content contains controllers, ... they could pollute/change the scope.
38015              // However, using ng-include on an element with additional content does not make sense...
38016              // Note: We can't remove them in the cloneAttchFn of $transclude as that
38017              // function is called before linking the content, which would apply child
38018              // directives to non existing elements.
38019              var clone = $transclude(newScope, function(clone) {
38020                cleanupLastIncludeContent();
38021                $animate.enter(clone, null, $element).done(afterAnimation);
38022              });
38023
38024              currentScope = newScope;
38025              currentElement = clone;
38026
38027              currentScope.$emit('$includeContentLoaded', src);
38028              scope.$eval(onloadExp);
38029            }, function() {
38030              if (scope.$$destroyed) return;
38031
38032              if (thisChangeId === changeCounter) {
38033                cleanupLastIncludeContent();
38034                scope.$emit('$includeContentError', src);
38035              }
38036            });
38037            scope.$emit('$includeContentRequested', src);
38038          } else {
38039            cleanupLastIncludeContent();
38040            ctrl.template = null;
38041          }
38042        });
38043      };
38044    }
38045  };
38046}];
38047
38048// This directive is called during the $transclude call of the first `ngInclude` directive.
38049// It will replace and compile the content of the element with the loaded template.
38050// We need this directive so that the element content is already filled when
38051// the link function of another directive on the same element as ngInclude
38052// is called.
38053var ngIncludeFillContentDirective = ['$compile',
38054  function($compile) {
38055    return {
38056      restrict: 'ECA',
38057      priority: -400,
38058      require: 'ngInclude',
38059      link: function(scope, $element, $attr, ctrl) {
38060        if (toString.call($element[0]).match(/SVG/)) {
38061          // WebKit: https://bugs.webkit.org/show_bug.cgi?id=135698 --- SVG elements do not
38062          // support innerHTML, so detect this here and try to generate the contents
38063          // specially.
38064          $element.empty();
38065          $compile(jqLiteBuildFragment(ctrl.template, window.document).childNodes)(scope,
38066              function namespaceAdaptedClone(clone) {
38067            $element.append(clone);
38068          }, {futureParentElement: $element});
38069          return;
38070        }
38071
38072        $element.html(ctrl.template);
38073        $compile($element.contents())(scope);
38074      }
38075    };
38076  }];
38077
38078/**
38079 * @ngdoc directive
38080 * @name ngInit
38081 * @restrict AC
38082 *
38082
38083 * @description
38084 * The `ngInit` directive allows you to evaluate an expression in the
38085 * current scope.
38086 *
38087 * <div class="alert alert-danger">
38088 * This directive can be abused to add unnecessary amounts of logic into your templates.
38089 * There are only a few appropriate uses of `ngInit`, such as for aliasing special properties of
38090 * {@link ng.directive:ngRepeat `ngRepeat`}, as seen in the demo below; and for injecting data via
38091 * server side scripting. Besides these few cases, you should use {@link guide/controller controllers}
38092 * rather than `ngInit` to initialize values on a scope.
38093 * </div>
38094 *
38095 * <div class="alert alert-warning">
38096 * **Note**: If you have assignment in `ngInit` along with a {@link ng.$filter `filter`}, make
38097 * sure you have parentheses to ensure correct operator precedence:
38098 * <pre class="prettyprint">
38099 * `<div ng-init="test1 = ($index | toString)"></div>`
38100 * </pre>
38101 * </div>
38102 *
38103 * @priority 450
38104 *
38105 * @element ANY
38106 * @param {expression} ngInit {@link guide/expression Expression} to eval.
38107 *
38108 * @example
38109   <example module="initExample" name="ng-init">
38110     <file name="index.html">
38111   <script>
38112     angular.module('initExample', [])
38113       .controller('ExampleController', ['$scope', function($scope) {
38114         $scope.list = [['a', 'b'], ['c', 'd']];
38115       }]);
38116   </script>
38117   <div ng-controller="ExampleController">
38118     <div ng-repeat="innerList in list" ng-init="outerIndex = $index">
38119       <div ng-repeat="value in innerList" ng-init="innerIndex = $index">
38120          <span class="example-init">list[ {{outerIndex}} ][ {{innerIndex}} ] = {{value}};</span>
38121       </div>
38122     </div>
38123   </div>
38124     </file>
38125     <file name="protractor.js" type="protractor">
38126       it('should alias index positions', function() {
38127         var elements = element.all(by.css('.example-init'));
38128         expect(elements.get(0).getText()).toBe('list[ 0 ][ 0 ] = a;');
38129         expect(elements.get(1).getText()).toBe('list[ 0 ][ 1 ] = b;');
38130         expect(elements.get(2).getText()).toBe('list[ 1 ][ 0 ] = c;');
38131         expect(elements.get(3).getText()).toBe('list[ 1 ][ 1 ] = d;');
38132       });
38133     </file>
38134   </example>
38135 */
38136var ngInitDirective = ngDirective({
38137  priority: 450,
38138  compile: function() {
38139    return {
38140      pre: function(scope, element, attrs) {
38141        scope.$eval(attrs.ngInit);
38142      }
38143    };
38144  }
38145});
38146
38147/**
38148 * @ngdoc directive
38149 * @name ngList
38150 *
38151 * @description
38152 * Text input that converts between a delimited string and an array of strings. The default
38153 * delimiter is a comma followed by a space - equivalent to `ng-list=", "`. You can specify a custom
38154 * delimiter as the value of the `ngList` attribute - for example, `ng-list=" | "`.
38155 *
38156 * The behaviour of the directive is affected by the use of the `ngTrim` attribute.
38157 * * If `ngTrim` is set to `"false"` then whitespace around both the separator and each
38158 *   list item is respected. This implies that the user of the directive is responsible for
38159 *   dealing with whitespace but also allows you to use whitespace as a delimiter, such as a
38160 *   tab or newline character.
38161 * * Otherwise whitespace around the delimiter is ignored when splitting (although it is respected
38162 *   when joining the list items back together) and whitespace around each list item is stripped
38163 *   before it is added to the model.
38164 *
38165 * ### Example with Validation
38166 *
38167 * <example name="ngList-directive" module="listExample">
38168 *   <file name="app.js">
38169 *      angular.module('listExample', [])
38170 *        .controller('ExampleController', ['$scope', function($scope) {
38171 *          $scope.names = ['morpheus', 'neo', 'trinity'];
38172 *        }]);
38173 *   </file>
38174 *   <file name="index.html">
38175 *    <form name="myForm" ng-controller="ExampleController">
38176 *      <label>List: <input name="namesInput" ng-model="names" ng-list required></label>
38177 *      <span role="alert">
38178 *        <span class="error" ng-show="myForm.namesInput.$error.required">
38179 *        Required!</span>
38180 *      </span>
38181 *      <br>
38182 *      <tt>names = {{names}}</tt><br/>
38183 *      <tt>myForm.namesInput.$valid = {{myForm.namesInput.$valid}}</tt><br/>
38184 *      <tt>myForm.namesInput.$error = {{myForm.namesInput.$error}}</tt><br/>
38185 *      <tt>myForm.$valid = {{myForm.$valid}}</tt><br/>
38186 *      <tt>myForm.$error.required = {{!!myForm.$error.required}}</tt><br/>
38187 *     </form>
38188 *   </file>
38189 *   <file name="protractor.js" type="protractor">
38190 *     var listInput = element(by.model('names'));
38191 *     var names = element(by.exactBinding('names'));
38192 *     var valid = element(by.binding('myForm.namesInput.$valid'));
38193 *     var error = element(by.css('span.error'));
38194 *
38195 *     it('should initialize to model', function() {
38196 *       expect(names.getText()).toContain('["morpheus","neo","trinity"]');
38197 *       expect(valid.getText()).toContain('true');
38198 *       expect(error.getCssValue('display')).toBe('none');
38199 *     });
38200 *
38201 *     it('should be invalid if empty', function() {
38202 *       listInput.clear();
38203 *       listInput.sendKeys('');
38204 *
38205 *       expect(names.getText()).toContain('');
38206 *       expect(valid.getText()).toContain('false');
38207 *       expect(error.getCssValue('display')).not.toBe('none');
38208 *     });
38209 *   </file>
38210 * </example>
38211 *
38212 * ### Example - splitting on newline
38213 * <example name="ngList-directive-newlines">
38214 *   <file name="index.html">
38215 *    <textarea ng-model="list" ng-list="&#10;" ng-trim="false"></textarea>
38216 *    <pre>{{ list | json }}</pre>
38217 *   </file>
38218 *   <file name="protractor.js" type="protractor">
38219 *     it("should split the text by newlines", function() {
38220 *       var listInput = element(by.model('list'));
38221 *       var output = element(by.binding('list | json'));
38222 *       listInput.sendKeys('abc\ndef\nghi');
38223 *       expect(output.getText()).toContain('[\n  "abc",\n  "def",\n  "ghi"\n]');
38224 *     });
38225 *   </file>
38226 * </example>
38227 *
38228 * @element input
38229 * @param {string=} ngList optional delimiter that should be used to split the value.
38230 */
38231var ngListDirective = function() {
38232  return {
38233    restrict: 'A',
38234    priority: 100,
38235    require: 'ngModel',
38236    link: function(scope, element, attr, ctrl) {
38237      var ngList = attr.ngList || ', ';
38238      var trimValues = attr.ngTrim !== 'false';
38239      var separator = trimValues ? trim(ngList) : ngList;
38240
38241      var parse = function(viewValue) {
38242        // If the viewValue is invalid (say required but empty) it will be `undefined`
38243        if (isUndefined(viewValue)) return;
38244
38245        var list = [];
38246
38247        if (viewValue) {
38248          forEach(viewValue.split(separator), function(value) {
38249            if (value) list.push(trimValues ? trim(value) : value);
38250          });
38251        }
38252
38253        return list;
38254      };
38255
38256      ctrl.$parsers.push(parse);
38257      ctrl.$formatters.push(function(value) {
38258        if (isArray(value)) {
38259          return value.join(ngList);
38260        }
38261
38262        return undefined;
38263      });
38264
38265      // Override the standard $isEmpty because an empty array means the input is empty.
38266      ctrl.$isEmpty = function(value) {
38267        return !value || !value.length;
38268      };
38269    }
38270  };
38271};
38272
38273/* global VALID_CLASS: true,
38274  INVALID_CLASS: true,
38275  PRISTINE_CLASS: true,
38276  DIRTY_CLASS: true,
38277  UNTOUCHED_CLASS: true,
38278  TOUCHED_CLASS: true,
38279  PENDING_CLASS: true,
38280  addSetValidityMethod: true,
38281  setupValidity: true,
38282  defaultModelOptions: false
38283*/
38284
38285
38286var VALID_CLASS = 'ng-valid',
38287    INVALID_CLASS = 'ng-invalid',
38288    PRISTINE_CLASS = 'ng-pristine',
38289    DIRTY_CLASS = 'ng-dirty',
38290    UNTOUCHED_CLASS = 'ng-untouched',
38291    TOUCHED_CLASS = 'ng-touched',
38292    EMPTY_CLASS = 'ng-empty',
38293    NOT_EMPTY_CLASS = 'ng-not-empty';
38294
38295var ngModelMinErr = minErr('ngModel');
38296
38297/**
38298 * @ngdoc type
38299 * @name ngModel.NgModelController
38300 *
38301 * @property {*} $viewValue The actual value from the control's view. For `input` elements, this is a
38302 * String. See {@link ngModel.NgModelController#$setViewValue} for information about when the $viewValue
38303 * is set.
38304 *
38305 * @property {*} $modelValue The value in the model that the control is bound to.
38306 *
38307 * @property {Array.<Function>} $parsers Array of functions to execute, as a pipeline, whenever
38308 *  the control updates the ngModelController with a new {@link ngModel.NgModelController#$viewValue
38309    `$viewValue`} from the DOM, usually via user input.
38310    See {@link ngModel.NgModelController#$setViewValue `$setViewValue()`} for a detailed lifecycle explanation.
38311    Note that the `$parsers` are not called when the bound ngModel expression changes programmatically.
38312
38313  The functions are called in array order, each passing
38314    its return value through to the next. The last return value is forwarded to the
38315    {@link ngModel.NgModelController#$validators `$validators`} collection.
38316
38317  Parsers are used to sanitize / convert the {@link ngModel.NgModelController#$viewValue
38318    `$viewValue`}.
38319
38320  Returning `undefined` from a parser means a parse error occurred. In that case,
38321    no {@link ngModel.NgModelController#$validators `$validators`} will run and the `ngModel`
38322    will be set to `undefined` unless {@link ngModelOptions `ngModelOptions.allowInvalid`}
38323    is set to `true`. The parse error is stored in `ngModel.$error.parse`.
38324
38325  This simple example shows a parser that would convert text input value to lowercase:
38326 * ```js
38327 * function parse(value) {
38328 *   if (value) {
38329 *     return value.toLowerCase();
38330 *   }
38331 * }
38332 * ngModelController.$parsers.push(parse);
38333 * ```
38334
38335 *
38336 * @property {Array.<Function>} $formatters Array of functions to execute, as a pipeline, whenever
38337    the bound ngModel expression changes programmatically. The `$formatters` are not called when the
38338    value of the control is changed by user interaction.
38339
38340  Formatters are used to format / convert the {@link ngModel.NgModelController#$modelValue
38341    `$modelValue`} for display in the control.
38342
38343  The functions are called in reverse array order, each passing the value through to the
38344    next. The last return value is used as the actual DOM value.
38345
38346  This simple example shows a formatter that would convert the model value to uppercase:
38347
38348 * ```js
38349 * function format(value) {
38350 *   if (value) {
38351 *     return value.toUpperCase();
38352 *   }
38353 * }
38354 * ngModel.$formatters.push(format);
38355 * ```
38356 *
38357 * @property {Object.<string, function>} $validators A collection of validators that are applied
38358 *      whenever the model value changes. The key value within the object refers to the name of the
38359 *      validator while the function refers to the validation operation. The validation operation is
38360 *      provided with the model value as an argument and must return a true or false value depending
38361 *      on the response of that validation.
38362 *
38363 * ```js
38364 * ngModel.$validators.validCharacters = function(modelValue, viewValue) {
38365 *   var value = modelValue || viewValue;
38366 *   return /[0-9]+/.test(value) &&
38367 *          /[a-z]+/.test(value) &&
38368 *          /[A-Z]+/.test(value) &&
38369 *          /\W+/.test(value);
38370 * };
38371 * ```
38372 *
38373 * @property {Object.<string, function>} $asyncValidators A collection of validations that are expected to
38374 *      perform an asynchronous validation (e.g. a HTTP request). The validation function that is provided
38375 *      is expected to return a promise when it is run during the model validation process. Once the promise
38376 *      is delivered then the validation status will be set to true when fulfilled and false when rejected.
38377 *      When the asynchronous validators are triggered, each of the validators will run in parallel and the model
38378 *      value will only be updated once all validators have been fulfilled. As long as an asynchronous validator
38379 *      is unfulfilled, its key will be added to the controllers `$pending` property. Also, all asynchronous validators
38380 *      will only run once all synchronous validators have passed.
38381 *
38382 * Please note that if $http is used then it is important that the server returns a success HTTP response code
38383 * in order to fulfill the validation and a status level of `4xx` in order to reject the validation.
38384 *
38385 * ```js
38386 * ngModel.$asyncValidators.uniqueUsername = function(modelValue, viewValue) {
38387 *   var value = modelValue || viewValue;
38388 *
38389 *   // Lookup user by username
38390 *   return $http.get('/api/users/' + value).
38391 *      then(function resolved() {
38392 *        //username exists, this means validation fails
38393 *        return $q.reject('exists');
38394 *      }, function rejected() {
38395 *        //username does not exist, therefore this validation passes
38396 *        return true;
38397 *      });
38398 * };
38399 * ```
38400 *
38401 * @property {Array.<Function>} $viewChangeListeners Array of functions to execute whenever the
38402 *     view value has changed. It is called with no arguments, and its return value is ignored.
38403 *     This can be used in place of additional $watches against the model value.
38404 *
38405 * @property {Object} $error An object hash with all failing validator ids as keys.
38406 * @property {Object} $pending An object hash with all pending validator ids as keys.
38407 *
38408 * @property {boolean} $untouched True if control has not lost focus yet.
38409 * @property {boolean} $touched True if control has lost focus.
38410 * @property {boolean} $pristine True if user has not interacted with the control yet.
38411 * @property {boolean} $dirty True if user has already interacted with the control.
38412 * @property {boolean} $valid True if there is no error.
38413 * @property {boolean}
38413 $invalid True if at least one error on the control.
38414 * @property {string} $name The name attribute of the control.
38415 *
38416 * @description
38417 *
38418 * `NgModelController` provides API for the {@link ngModel `ngModel`} directive.
38419 * The controller contains services for data-binding, validation, CSS updates, and value formatting
38420 * and parsing. It purposefully does not contain any logic which deals with DOM rendering or
38421 * listening to DOM events.
38422 * Such DOM related logic should be provided by other directives which make use of
38423 * `NgModelController` for data-binding to control elements.
38424 * Angular provides this DOM logic for most {@link input `input`} elements.
38425 * At the end of this page you can find a {@link ngModel.NgModelController#custom-control-example
38426 * custom control example} that uses `ngModelController` to bind to `contenteditable` elements.
38427 *
38428 * @example
38429 * ### Custom Control Example
38430 * This example shows how to use `NgModelController` with a custom control to achieve
38431 * data-binding. Notice how different directives (`contenteditable`, `ng-model`, and `required`)
38432 * collaborate together to achieve the desired result.
38433 *
38434 * `contenteditable` is an HTML5 attribute, which tells the browser to let the element
38435 * contents be edited in place by the user.
38436 *
38437 * We are using the {@link ng.service:$sce $sce} service here and include the {@link ngSanitize $sanitize}
38438 * module to automatically remove "bad" content like inline event listener (e.g. `<span onclick="...">`).
38439 * However, as we are using `$sce` the model can still decide to provide unsafe content if it marks
38440 * that content using the `$sce` service.
38441 *
38442 * <example name="NgModelController" module="customControl" deps="angular-sanitize.js">
38443    <file name="style.css">
38444      [contenteditable] {
38445        border: 1px solid black;
38446        background-color: white;
38447        min-height: 20px;
38448      }
38449
38450      .ng-invalid {
38451        border: 1px solid red;
38452      }
38453
38454    </file>
38455    <file name="script.js">
38456      angular.module('customControl', ['ngSanitize']).
38457        directive('contenteditable', ['$sce', function($sce) {
38458          return {
38459            restrict: 'A', // only activate on element attribute
38460            require: '?ngModel', // get a hold of NgModelController
38461            link: function(scope, element, attrs, ngModel) {
38462              if (!ngModel) return; // do nothing if no ng-model
38463
38464              // Specify how UI should be updated
38465              ngModel.$render = function() {
38466                element.html($sce.getTrustedHtml(ngModel.$viewValue || ''));
38467              };
38468
38469              // Listen for change events to enable binding
38470              element.on('blur keyup change', function() {
38471                scope.$evalAsync(read);
38472              });
38473              read(); // initialize
38474
38475              // Write data to the model
38476              function read() {
38477                var html = element.html();
38478                // When we clear the content editable the browser leaves a <br> behind
38479                // If strip-br attribute is provided then we strip this out
38480                if (attrs.stripBr && html === '<br>') {
38481                  html = '';
38482                }
38483                ngModel.$setViewValue(html);
38484              }
38485            }
38486          };
38487        }]);
38488    </file>
38489    <file name="index.html">
38490      <form name="myForm">
38491       <div contenteditable
38492            name="myWidget" ng-model="userContent"
38493            strip-br="true"
38494            required>Change me!</div>
38495        <span ng-show="myForm.myWidget.$error.required">Required!</span>
38496       <hr>
38497       <textarea ng-model="userContent" aria-label="Dynamic textarea"></textarea>
38498      </form>
38499    </file>
38500    <file name="protractor.js" type="protractor">
38501    it('should data-bind and become invalid', function() {
38502      if (browser.params.browser === 'safari' || browser.params.browser === 'firefox') {
38503        // SafariDriver can't handle contenteditable
38504        // and Firefox driver can't clear contenteditables very well
38505        return;
38506      }
38507      var contentEditable = element(by.css('[contenteditable]'));
38508      var content = 'Change me!';
38509
38510      expect(contentEditable.getText()).toEqual(content);
38511
38512      contentEditable.clear();
38513      contentEditable.sendKeys(protractor.Key.BACK_SPACE);
38514      expect(contentEditable.getText()).toEqual('');
38515      expect(contentEditable.getAttribute('class')).toMatch(/ng-invalid-required/);
38516    });
38517    </file>
38518 * </example>
38519 *
38520 *
38521 */
38522NgModelController.$inject = ['$scope', '$exceptionHandler', '$attrs', '$element', '$parse', '$animate', '$timeout', '$q', '$interpolate'];
38523function NgModelController($scope, $exceptionHandler, $attr, $element, $parse, $animate, $timeout, $q, $interpolate) {
38524  this.$viewValue = Number.NaN;
38525  this.$modelValue = Number.NaN;
38526  this.$$rawModelValue = undefined; // stores the parsed modelValue / model set from scope regardless of validity.
38527  this.$validators = {};
38528  this.$asyncValidators = {};
38529  this.$parsers = [];
38530  this.$formatters = [];
38531  this.$viewChangeListeners = [];
38532  this.$untouched = true;
38533  this.$touched = false;
vendor: 4,653 bytes, lines 38534-38661
38534  this.$pristine = true;
38535  this.$dirty = false;
38536  this.$valid = true;
38537  this.$invalid = false;
38538  this.$error = {}; // keep invalid keys here
38539  this.$$success = {}; // keep valid keys here
38540  this.$pending = undefined; // keep pending keys here
38541  this.$name = $interpolate($attr.name || '', false)($scope);
38542  this.$$parentForm = nullFormCtrl;
38543  this.$options = defaultModelOptions;
38544
38545  this.$$parsedNgModel = $parse($attr.ngModel);
38546  this.$$parsedNgModelAssign = this.$$parsedNgModel.assign;
38547  this.$$ngModelGet = this.$$parsedNgModel;
38548  this.$$ngModelSet = this.$$parsedNgModelAssign;
38549  this.$$pendingDebounce = null;
38550  this.$$parserValid = undefined;
38551
38552  this.$$currentValidationRunId = 0;
38553
38554  this.$$scope = $scope;
38555  this.$$attr = $attr;
38556  this.$$element = $element;
38557  this.$$animate = $animate;
38558  this.$$timeout = $timeout;
38559  this.$$parse = $parse;
38560  this.$$q = $q;
38561  this.$$exceptionHandler = $exceptionHandler;
38562
38563  setupValidity(this);
38564  setupModelWatcher(this);
38565}
38566
38567NgModelController.prototype = {
38568  $$initGetterSetters: function() {
38569    if (this.$options.getOption('getterSetter')) {
38570      var invokeModelGetter = this.$$parse(this.$$attr.ngModel + '()'),
38571          invokeModelSetter = this.$$parse(this.$$attr.ngModel + '($$$p)');
38572
38573      this.$$ngModelGet = function($scope) {
38574        var modelValue = this.$$parsedNgModel($scope);
38575        if (isFunction(modelValue)) {
38576          modelValue = invokeModelGetter($scope);
38577        }
38578        return modelValue;
38579      };
38580      this.$$ngModelSet = function($scope, newValue) {
38581        if (isFunction(this.$$parsedNgModel($scope))) {
38582          invokeModelSetter($scope, {$$$p: newValue});
38583        } else {
38584          this.$$parsedNgModelAssign($scope, newValue);
38585        }
38586      };
38587    } else if (!this.$$parsedNgModel.assign) {
38588      throw ngModelMinErr('nonassign', 'Expression \'{0}\' is non-assignable. Element: {1}',
38589          this.$$attr.ngModel, startingTag(this.$$element));
38590    }
38591  },
38592
38593
38594  /**
38595   * @ngdoc method
38596   * @name ngModel.NgModelController#$render
38597   *
38598   * @description
38599   * Called when the view needs to be updated. It is expected that the user of the ng-model
38600   * directive will implement this method.
38601   *
38602   * The `$render()` method is invoked in the following situations:
38603   *
38604   * * `$rollbackViewValue()` is called.  If we are rolling back the view value to the last
38605   *   committed value then `$render()` is called to update the input control.
38606   * * The value referenced by `ng-model` is changed programmatically and both the `$modelValue` and
38607   *   the `$viewValue` are different from last time.
38608   *
38609   * Since `ng-model` does not do a deep watch, `$render()` is only invoked if the values of
38610   * `$modelValue` and `$viewValue` are actually different from their previous values. If `$modelValue`
38611   * or `$viewValue` are objects (rather than a string or number) then `$render()` will not be
38612   * invoked if you only change a property on the objects.
38613   */
38614  $render: noop,
38615
38616  /**
38617   * @ngdoc method
38618   * @name ngModel.NgModelController#$isEmpty
38619   *
38620   * @description
38621   * This is called when we need to determine if the value of an input is empty.
38622   *
38623   * For instance, the required directive does this to work out if the input has data or not.
38624   *
38625   * The default `$isEmpty` function checks whether the value is `undefined`, `''`, `null` or `NaN`.
38626   *
38627   * You can override this for input directives whose concept of being empty is different from the
38628   * default. The `checkboxInputType` directive does this because in its case a value of `false`
38629   * implies empty.
38630   *
38631   * @param {*} value The value of the input to check for emptiness.
38632   * @returns {boolean} True if `value` is "empty".
38633   */
38634  $isEmpty: function(value) {
38635    // eslint-disable-next-line no-self-compare
38636    return isUndefined(value) || value === '' || value === null || value !== value;
38637  },
38638
38639  $$updateEmptyClasses: function(value) {
38640    if (this.$isEmpty(value)) {
38641      this.$$animate.removeClass(this.$$element, NOT_EMPTY_CLASS);
38642      this.$$animate.addClass(this.$$element, EMPTY_CLASS);
38643    } else {
38644      this.$$animate.removeClass(this.$$element, EMPTY_CLASS);
38645      this.$$animate.addClass(this.$$element, NOT_EMPTY_CLASS);
38646    }
38647  },
38648
38649  /**
38650   * @ngdoc method
38651   * @name ngModel.NgModelController#$setPristine
38652   *
38653   * @description
38654   * Sets the control to its pristine state.
38655   *
38656   * This method can be called to remove the `ng-dirty` class and set the control to its pristine
38657   * state (`ng-pristine` class). A model is considered to be pristine when the control
38658   * has not been changed from when first compiled.
38659   */
38660  $setPristine: function() {
38661    this.$dirty = false;
38662    this.$pristine = true;
38663    this.$$animate.removeClass(this.$$element, DIRTY_CLASS);
38664    this.$$animate.addClass(this.$$element, PRISTINE_CLASS);
38665  },
38666
38667  /**
38668   * @ngdoc method
38669   * @name ngModel.NgModelController#$setDirty
38670   *
38671   * @description
38672   * Sets the control to its dirty state.
38673   *
38674   * This method can be called to remove the `ng-pristine` class and set the control to its dirty
38675   * state (`ng-dirty` class). A model is considered to be dirty when the control has been changed
38676   * from when first compiled.
38677   */
38678  $setDirty: function() {
38679    this.$dirty = true;
38680    this.$pristine = false;
38681    this.$$animate.removeClass(this.$$element, PRISTINE_CLASS);
38682    this.$$animate.addClass(this.$$element, DIRTY_CLASS);
38683    this.$$parentForm.$setDirty();
38684  },
38685
38686  /**
38687   * @ngdoc method
38688   * @name ngModel.NgModelController#$setUntouched
38689   *
38690   * @description
38691   * Sets the control to its untouched state.
38692   *
38693   * This method can be called to remove the `ng-touched` class and set the control to its
38694   * untouched state (`ng-untouched` class). Upon compilation, a model is set as untouched
38695   * by default, however this function can be used to restore that state if the model has
38696   * already been touched by the user.
38697   */
38698  $setUntouched: function() {
38699    this.$touched = false;
38700    this.$untouched = true;
38701    this.$$animate.setClass(this.$$element, UNTOUCHED_CLASS, TOUCHED_CLASS);
38702  },
38703
38704  /**
38705   * @ngdoc method
38706   * @name ngModel.NgModelController#$setTouched
38707   *
38708   * @description
38709   * Sets the control to its touched state.
38710   *
38711   * This method can be called to remove the `ng-untouched` class and set the control to its
38712   * touched state (`ng-touched` class). A model is considered to be touched when the user has
38713   * first focused the control element and then shifted focus away from the control (blur event).
38714   */
38715  $setTouched: function() {
38716    this.$touched = true;
38717    this.$untouched = false;
38718    this.$$animate.setClass(this.$$element, TOUCHED_CLASS, UNTOUCHED_CLASS);
38719  },
38720
38721  /**
38722   * @ngdoc method
38723   * @name ngModel.NgModelController#$rollbackViewValue
38724   *
38725   * @description
38726   * Cancel an update and reset the input element's value to prevent an update to the `$modelValue`,
38727   * which may be caused by a pending debounced event or because the input is waiting for some
38728   * future event.
38729   *
38730   * If you have an input that uses `ng-model-options` to set up debounced updates or updates that
38731   * depend on special events such as `blur`, there can be a period when the `$viewValue` is out of
38732   * sync with the ngModel's `$modelValue`.
38733   *
38734   * In this case, you can use `$rollbackViewValue()` to manually cancel the debounced / future update
38735   * and reset the input to the last committed view value.
38736   *
38737   * It is also possible that you run into difficulties if you try to update the ngModel's `$modelValue`
38738   * programmatically before these debounced/future events have resolved/occurred, because Angular's
38739   * dirty checking mechanism is not able to tell whether the model has actually changed or not.
38740   *
38741   * The `$rollbackViewValue()` method should be called before programmatically changing the model of an
38742   * input which may have such events pending. This is important in order to make sure that the
38743   * input field will be updated with the new model value and any pending operations are cancelled.
38744   *
38745   * <example name="ng-model-cancel-update" module="cancel-update-example">
38746   *   <file name="app.js">
38747   *     angular.module('cancel-update-example', [])
38748   *
38749   *     .controller('CancelUpdateController', ['$scope', function($scope) {
38750   *       $scope.model = {value1: '', value2: ''};
38751   *
38752   *       $scope.setEmpty = function(e, value, rollback) {
38753   *         if (e.keyCode === 27) {
38754   *           e.preventDefault();
38755   *           if (rollback) {
38756   *             $scope.myForm[value].$rollbackViewValue();
38757   *           }
38758   *           $scope.model[value] = '';
38759   *         }
38760   *       };
38761   *     }]);
38762   *   </file>
38763   *   <file name="index.html">
38764   *     <div ng-controller="CancelUpdateController">
38765   *       <p>
38765Both of these inputs are only updated if they are blurred. Hitting escape should
38766   *       empty them. Follow these steps and observe the difference:</p>
38767   *       <ol>
38768   *         <li>Type something in the input. You will see that the model is not yet updated</li>
38769   *         <li>Press the Escape key.
38770   *           <ol>
38771   *             <li> In the first example, nothing happens, because the model is already '', and no
38772   *             update is detected. If you blur the input, the model will be set to the current view.
38773   *             </li>
38774   *             <li> In the second example, the pending update is cancelled, and the input is set back
38775   *             to the last committed view value (''). Blurring the input does nothing.
38776   *             </li>
38777   *           </ol>
38778   *         </li>
38779   *       </ol>
38780   *
38781   *       <form name="myForm" ng-model-options="{ updateOn: 'blur' }">
38782   *         <div>
38783   *           <p id="inputDescription1">Without $rollbackViewValue():</p>
38784   *           <input name="value1" aria-describedby="inputDescription1" ng-model="model.value1"
38785   *                  ng-keydown="setEmpty($event, 'value1')">
38786   *           value1: "{{ model.value1 }}"
38787   *         </div>
38788   *
38789   *         <div>
38790   *           <p id="inputDescription2">With $rollbackViewValue():</p>
38791   *           <input name="value2" aria-describedby="inputDescription2" ng-model="model.value2"
38792   *                  ng-keydown="setEmpty($event, 'value2', true)">
38793   *           value2: "{{ model.value2 }}"
38794   *         </div>
38795   *       </form>
38796   *     </div>
38797   *   </file>
38798       <file name="style.css">
38799          div {
38800            display: table-cell;
38801          }
38802          div:nth-child(1) {
38803            padding-right: 30px;
38804          }
38805
38806        </file>
38807   * </example>
38808   */
38809  $rollbackViewValue: function() {
38810    this.$$timeout.cancel(this.$$pendingDebounce);
38811    this.$viewValue = this.$$lastCommittedViewValue;
38812    this.$render();
38813  },
38814
38815  /**
38816   * @ngdoc method
38817   * @name ngModel.NgModelController#$validate
38818   *
38819   * @description
38820   * Runs each of the registered validators (first synchronous validators and then
38821   * asynchronous validators).
38822   * If the validity changes to invalid, the model will be set to `undefined`,
38823   * unless {@link ngModelOptions `ngModelOptions.allowInvalid`} is `true`.
38824   * If the validity changes to valid, it will set the model to the last available valid
38825   * `$modelValue`, i.e. either the last parsed value or the last value set from the scope.
38826   */
38827  $validate: function() {
38828    // ignore $validate before model is initialized
38829    if (isNumberNaN(this.$modelValue)) {
38830      return;
38831    }
38832
38833    var viewValue = this.$$lastCommittedViewValue;
38834    // Note: we use the $$rawModelValue as $modelValue might have been
38835    // set to undefined during a view -> model update that found validation
38836    // errors. We can't parse the view here, since that could change
38837    // the model although neither viewValue nor the model on the scope changed
38838    var modelValue = this.$$rawModelValue;
38839
38840    var prevValid = this.$valid;
38841    var prevModelValue = this.$modelValue;
38842
38843    var allowInvalid = this.$options.getOption('allowInvalid');
38844
38845    var that = this;
38846    this.$$runValidators(modelValue, viewValue, function(allValid) {
38847      // If there was no change in validity, don't update the model
38848      // This prevents changing an invalid modelValue to undefined
38849      if (!allowInvalid && prevValid !== allValid) {
38850        // Note: Don't check this.$valid here, as we could have
38851        // external validators (e.g. calculated on the server),
38852        // that just call $setValidity and need the model value
38853        // to calculate their validity.
38854        that.$modelValue = allValid ? modelValue : undefined;
38855
38856        if (that.$modelValue !== prevModelValue) {
38857          that.$$writeModelToScope();
38858        }
38859      }
38860    });
38861  },
38862
38863  $$runValidators: function(modelValue, viewValue, doneCallback) {
38864    this.$$currentValidationRunId++;
38865    var localValidationRunId = this.$$currentValidationRunId;
38866    var that = this;
38867
38868    // check parser error
38869    if (!processParseErrors()) {
38870      validationDone(false);
38871      return;
38872    }
38873    if (!processSyncValidators()) {
38874      validationDone(false);
38875      return;
38876    }
38877    processAsyncValidators();
38878
38879    function processParseErrors() {
38880      var errorKey = that.$$parserName || 'parse';
38881      if (isUndefined(that.$$parserValid)) {
vendor: 9,425 bytes, lines 38882-39121
38882        setValidity(errorKey, null);
38883      } else {
38884        if (!that.$$parserValid) {
38885          forEach(that.$validators, function(v, name) {
38886            setValidity(name, null);
38887          });
38888          forEach(that.$asyncValidators, function(v, name) {
38889            setValidity(name, null);
38890          });
38891        }
38892        // Set the parse error last, to prevent unsetting it, should a $validators key == parserName
38893        setValidity(errorKey, that.$$parserValid);
38894        return that.$$parserValid;
38895      }
38896      return true;
38897    }
38898
38899    function processSyncValidators() {
38900      var syncValidatorsValid = true;
38901      forEach(that.$validators, function(validator, name) {
38902        var result = Boolean(validator(modelValue, viewValue));
38903        syncValidatorsValid = syncValidatorsValid && result;
38904        setValidity(name, result);
38905      });
38906      if (!syncValidatorsValid) {
38907        forEach(that.$asyncValidators, function(v, name) {
38908          setValidity(name, null);
38909        });
38910        return false;
38911      }
38912      return true;
38913    }
38914
38915    function processAsyncValidators() {
38916      var validatorPromises = [];
38917      var allValid = true;
38918      forEach(that.$asyncValidators, function(validator, name) {
38919        var promise = validator(modelValue, viewValue);
38920        if (!isPromiseLike(promise)) {
38921          throw ngModelMinErr('nopromise',
38922            'Expected asynchronous validator to return a promise but got \'{0}\' instead.', promise);
38923        }
38924        setValidity(name, undefined);
38925        validatorPromises.push(promise.then(function() {
38926          setValidity(name, true);
38927        }, function() {
38928          allValid = false;
38929          setValidity(name, false);
38930        }));
38931      });
38932      if (!validatorPromises.length) {
38933        validationDone(true);
38934      } else {
38935        that.$$q.all(validatorPromises).then(function() {
38936          validationDone(allValid);
38937        }, noop);
38938      }
38939    }
38940
38941    function setValidity(name, isValid) {
38942      if (localValidationRunId === that.$$currentValidationRunId) {
38943        that.$setValidity(name, isValid);
38944      }
38945    }
38946
38947    function validationDone(allValid) {
38948      if (localValidationRunId === that.$$currentValidationRunId) {
38949
38950        doneCallback(allValid);
38951      }
38952    }
38953  },
38954
38955  /**
38956   * @ngdoc method
38957   * @name ngModel.NgModelController#$commitViewValue
38958   *
38959   * @description
38960   * Commit a pending update to the `$modelValue`.
38961   *
38962   * Updates may be pending by a debounced event or because the input is waiting for a some future
38963   * event defined in `ng-model-options`. this method is rarely needed as `NgModelController`
38964   * usually handles calling this in response to input events.
38965   */
38966  $commitViewValue: function() {
38967    var viewValue = this.$viewValue;
38968
38969    this.$$timeout.cancel(this.$$pendingDebounce);
38970
38971    // If the view value has not changed then we should just exit, except in the case where there is
38972    // a native validator on the element. In this case the validation state may have changed even though
38973    // the viewValue has stayed empty.
38974    if (this.$$lastCommittedViewValue === viewValue && (viewValue !== '' || !this.$$hasNativeValidators)) {
38975      return;
38976    }
38977    this.$$updateEmptyClasses(viewValue);
38978    this.$$lastCommittedViewValue = viewValue;
38979
38980    // change to dirty
38981    if (this.$pristine) {
38982      this.$setDirty();
38983    }
38984    this.$$parseAndValidate();
38985  },
38986
38987  $$parseAndValidate: function() {
38988    var viewValue = this.$$lastCommittedViewValue;
38989    var modelValue = viewValue;
38990    var that = this;
38991
38992    this.$$parserValid = isUndefined(modelValue) ? undefined : true;
38993
38994    if (this.$$parserValid) {
38995      for (var i = 0; i < this.$parsers.length; i++) {
38996        modelValue = this.$parsers[i](modelValue);
38997        if (isUndefined(modelValue)) {
38998          this.$$parserValid = false;
38999          break;
39000        }
39001      }
39002    }
39003    if (isNumberNaN(this.$modelValue)) {
39004      // this.$modelValue has not been touched yet...
39005      this.$modelValue = this.$$ngModelGet(this.$$scope);
39006    }
39007    var prevModelValue = this.$modelValue;
39008    var allowInvalid = this.$options.getOption('allowInvalid');
39009    this.$$rawModelValue = modelValue;
39010
39011    if (allowInvalid) {
39012      this.$modelValue = modelValue;
39013      writeToModelIfNeeded();
39014    }
39015
39016    // Pass the $$lastCommittedViewValue here, because the cached viewValue might be out of date.
39017    // This can happen if e.g. $setViewValue is called from inside a parser
39018    this.$$runValidators(modelValue, this.$$lastCommittedViewValue, function(allValid) {
39019      if (!allowInvalid) {
39020        // Note: Don't check this.$valid here, as we could have
39021        // external validators (e.g. calculated on the server),
39022        // that just call $setValidity and need the model value
39023        // to calculate their validity.
39024        that.$modelValue = allValid ? modelValue : undefined;
39025        writeToModelIfNeeded();
39026      }
39027    });
39028
39029    function writeToModelIfNeeded() {
39030      if (that.$modelValue !== prevModelValue) {
39031        that.$$writeModelToScope();
39032      }
39033    }
39034  },
39035
39036  $$writeModelToScope: function() {
39037    this.$$ngModelSet(this.$$scope, this.$modelValue);
39038    forEach(this.$viewChangeListeners, function(listener) {
39039      try {
39040        listener();
39041      } catch (e) {
39042        // eslint-disable-next-line no-invalid-this
39043        this.$$exceptionHandler(e);
39044      }
39045    }, this);
39046  },
39047
39048  /**
39049   * @ngdoc method
39050   * @name ngModel.NgModelController#$setViewValue
39051   *
39052   * @description
39053   * Update the view value.
39054   *
39055   * This method should be called when a control wants to change the view value; typically,
39056   * this is done from within a DOM event handler. For example, the {@link ng.directive:input input}
39057   * directive calls it when the value of the input changes and {@link ng.directive:select select}
39058   * calls it when an option is selected.
39059   *
39060   * When `$setViewValue` is called, the new `value` will be staged for committing through the `$parsers`
39061   * and `$validators` pipelines. If there are no special {@link ngModelOptions} specified then the staged
39062   * value is sent directly for processing through the `$parsers` pipeline. After this, the `$validators` and
39063   * `$asyncValidators` are called and the value is applied to `$modelValue`.
39064   * Finally, the value is set to the **expression** specified in the `ng-model` attribute and
39065   * all the registered change listeners, in the `$viewChangeListeners` list are called.
39066   *
39067   * In case the {@link ng.directive:ngModelOptions ngModelOptions} directive is used with `updateOn`
39068   * and the `default` trigger is not listed, all those actions will remain pending until one of the
39069   * `updateOn` events is triggered on the DOM element.
39070   * All these actions will be debounced if the {@link ng.directive:ngModelOptions ngModelOptions}
39071   * directive is used with a custom debounce for this particular event.
39072   * Note that a `$digest` is only triggered once the `updateOn` events are fired, or if `debounce`
39073   * is specified, once the timer runs out.
39074   *
39075   * When used with standard inputs, the view value will always be a string (which is in some cases
39076   * parsed into another type, such as a `Date` object for `input[date]`.)
39077   * However, custom controls might also pass objects to this method. In this case, we should make
39078   * a copy of the object before passing it to `$setViewValue`. This is because `ngModel` does not
39079   * perform a deep watch of objects, it only looks for a change of identity. If you only change
39080   * the property of the object then ngModel will not realize that the object has changed and
39081   * will not invoke the `$parsers` and `$validators` pipelines. For this reason, you should
39082   * not change properties of the copy once it has been passed to `$setViewValue`.
39083   * Otherwise you may cause the model value on the scope to change incorrectly.
39084   *
39085   * <div class="alert alert-info">
39086   * In any case, the value passed to the method should always reflect the current value
39087   * of the control. For example, if you are calling `$setViewValue` for an input element,
39088   * you should pass the input DOM value. Otherwise, the control and the scope model become
39089   * out of sync. It's also important to note that `$setViewValue` does not call `$render` or change
39090   * the control's DOM value in any way. If we want to change the control's DOM value
39091   * programmatically, we should update the `ngModel` scope expression. Its new value will be
39092   * picked up by the model controller, which will run it through the `$formatters`, `$render` it
39093   * to update the DOM, and finally call `$validate` on it.
39094   * </div>
39095   *
39096   * @param {*} value value from the view.
39097   * @param {string} trigger Event that triggered the update.
39098   */
39099  $setViewValue: function(value, trigger) {
39100    this.$viewValue = value;
39101    if (this.$options.getOption('updateOnDefault')) {
39102      this.$$debounceViewValueCommit(trigger);
39103    }
39104  },
39105
39106  $$debounceViewValueCommit: function(trigger) {
39107    var debounceDelay = this.$options.getOption('debounce');
39108
39109    if (isNumber(debounceDelay[trigger])) {
39110      debounceDelay = debounceDelay[trigger];
39111    } else if (isNumber(debounceDelay['default'])) {
39112      debounceDelay = debounceDelay['default'];
39113    }
39114
39115    this.$$timeout.cancel(this.$$pendingDebounce);
39116    var that = this;
39117    if (debounceDelay > 0) { // this fails if debounceDelay is an object
39118      this.$$pendingDebounce = this.$$timeout(function() {
39119        that.$commitViewValue();
39120      }, debounceDelay);
39121    }
39121 else if (this.$$scope.$root.$$phase) {
39122      this.$commitViewValue();
39123    } else {
39124      this.$$scope.$apply(function() {
39125        that.$commitViewValue();
39126      });
39127    }
39128  },
39129
39130  /**
39131   * @ngdoc method
39132   *
39133   * @name ngModel.NgModelController#$overrideModelOptions
39134   *
39135   * @description
39136   *
39137   * Override the current model options settings programmatically.
39138   *
39139   * The previous `ModelOptions` value will not be modified. Instead, a
39140   * new `ModelOptions` object will inherit from the previous one overriding
39141   * or inheriting settings that are defined in the given parameter.
39142   *
39143   * See {@link ngModelOptions} for information about what options can be specified
39144   * and how model option inheritance works.
39145   *
39146   * @param {Object} options a hash of settings to override the previous options
39147   *
39148   */
39149  $overrideModelOptions: function(options) {
39150    this.$options = this.$options.createChild(options);
39151  }
39152};
39153
39154function setupModelWatcher(ctrl) {
39155  // model -> value
39156  // Note: we cannot use a normal scope.$watch as we want to detect the following:
39157  // 1. scope value is 'a'
39158  // 2. user enters 'b'
39159  // 3. ng-change kicks in and reverts scope value to 'a'
39160  //    -> scope value did not change since the last digest as
39161  //       ng-change executes in apply phase
39162  // 4. view should be changed back to 'a'
39163  ctrl.$$scope.$watch(function ngModelWatch() {
39164    var modelValue = ctrl.$$ngModelGet(ctrl.$$scope);
39165
39166    // if scope model value and ngModel value are out of sync
39167    // TODO(perf): why not move this to the action fn?
39168    if (modelValue !== ctrl.$modelValue &&
39169       // checks for NaN is needed to allow setting the model to NaN when there's an asyncValidator
39170        // eslint-disable-next-line no-self-compare
39171       (ctrl.$modelValue === ctrl.$modelValue || modelValue === modelValue)
39172    ) {
39173      ctrl.$modelValue = ctrl.$$rawModelValue = modelValue;
39174      ctrl.$$parserValid = undefined;
39175
39176      var formatters = ctrl.$formatters,
39177          idx = formatters.length;
39178
39179      var viewValue = modelValue;
39180      while (idx--) {
39181        viewValue = formatters[idx](viewValue);
39182      }
39183      if (ctrl.$viewValue !== viewValue) {
39184        ctrl.$$updateEmptyClasses(viewValue);
39185        ctrl.$viewValue = ctrl.$$lastCommittedViewValue = viewValue;
39186        ctrl.$render();
39187
39188        // It is possible that model and view value have been updated during render
39189        ctrl.$$runValidators(ctrl.$modelValue, ctrl.$viewValue, noop);
39190      }
39191    }
39192
39193    return modelValue;
39194  });
39195}
39196
39197/**
39198 * @ngdoc method
39199 * @name ngModel.NgModelController#$setValidity
39200 *
39201 * @description
39202 * Change the validity state, and notify the form.
39203 *
39204 * This method can be called within $parsers/$formatters or a custom validation implementation.
39205 * However, in most cases it should be sufficient to use the `ngModel.$validators` and
39206 * `ngModel.$asyncValidators` collections which will call `$setValidity` automatically.
39207 *
39208 * @param {string} validationErrorKey Name of the validator. The `validationErrorKey` will be assigned
39209 *        to either `$error[validationErrorKey]` or `$pending[validationErrorKey]`
39210 *        (for unfulfilled `$asyncValidators`), so that it is available for data-binding.
39211 *        The `validationErrorKey` should be in camelCase and will get converted into dash-case
39212 *        for class name. Example: `myError` will result in `ng-valid-my-error` and `ng-invalid-my-error`
39213 *        class and can be bound to as  `{{someForm.someControl.$error.myError}}` .
39214 * @param {boolean} isValid Whether the current state is valid (true), invalid (false), pending (undefined),
39215 *                          or skipped (null). Pending is used for unfulfilled `$asyncValidators`.
39216 *                          Skipped is used by Angular when validators do not run because of parse errors and
39217 *                          when `$asyncValidators` do not run because any of the `$validators` failed.
39218 */
39219addSetValidityMethod({
39220  clazz: NgModelController,
39221  set: function(object, property) {
39222    object[property] = true;
39223  },
39224  unset: function(object, property) {
39225    delete object[property];
39226  }
39227});
39228
39229
39230/**
39231 * @ngdoc directive
39232 * @name ngModel
39233 *
39234 * @element input
39235 * @priority 1
39236 *
39237 * @description
39238 * The `ngModel` directive binds an `input`,`select`, `textarea` (or custom form control) to a
39239 * property on the scope using {@link ngModel.NgModelController NgModelController},
39240 * which is created and exposed by this directive.
39241 *
39242 * `ngModel` is responsible for:
39243 *
39244 * - Binding the view into the model, which other directives such as `input`, `textarea` or `select`
39245 *   require.
39246 * - Providing validation behavior (i.e. required, number, email, url).
39247 * - Keeping the state of the control (valid/invalid, dirty/pristine, touched/untouched, validation errors).
39248 * - Setting related css classes on the element (`ng-valid`, `ng-invalid`, `ng-dirty`, `ng-pristine`, `ng-touched`,
39249 *   `ng-untouched`, `ng-empty`, `ng-not-empty`) including animations.
39250 * - Registering the control with its parent {@link ng.directive:form form}.
39251 *
39252 * Note: `ngModel` will try to bind to the property given by evaluating the expression on the
39253 * current scope. If the property doesn't already exist on this scope, it will be created
39254 * implicitly and added to the scope.
39255 *
39256 * For best practices on using `ngModel`, see:
39257 *
39258 *  - [Understanding Scopes](https://github.com/angular/angular.js/wiki/Understanding-Scopes)
39259 *
39260 * For basic examples, how to use `ngModel`, see:
39261 *
39262 *  - {@link ng.directive:input input}
39263 *    - {@link input[text] text}
39264 *    - {@link input[checkbox] checkbox}
39265 *    - {@link input[radio] radio}
39266 *    - {@link input[number] number}
39267 *    - {@link input[email] email}
39268 *    - {@link input[url] url}
39269 *    - {@link input[date] date}
39270 *    - {@link input[datetime-local] datetime-local}
39271 *    - {@link input[time] time}
39272 *    - {@link input[month] month}
39273 *    - {@link input[week] week}
39274 *  - {@link ng.directive:select select}
39275 *  - {@link ng.directive:textarea textarea}
39276 *
39277 * # Complex Models (objects or collections)
39278 *
39279 * By default, `ngModel` watches the model by reference, not value. This is important to know when
39280 * binding inputs to models that are objects (e.g. `Date`) or collections (e.g. arrays). If only properties of the
39281 * object or collection change, `ngModel` will not be notified and so the input will not be  re-rendered.
39282 *
39283 * The model must be assigned an entirely new object or collection before a re-rendering will occur.
39284 *
39285 * Some directives have options that will cause them to use a custom `$watchCollection` on the model expression
39286 * - for example, `ngOptions` will do so when a `track by` clause is included in the comprehension expression or
39287 * if the select is given the `multiple` attribute.
39288 *
39289 * The `$watchCollection()` method only does a shallow comparison, meaning that changing properties deeper than the
39290 * first level of the object (or only changing the properties of an item in the collection if it's an array) will still
39291 * not trigger a re-rendering of the model.
39292 *
39293 * # CSS classes
39294 * The following CSS classes are added and removed on the associated input/select/textarea element
39295 * depending on the validity of the model.
39296 *
39297 *  - `ng-valid`: the model is valid
39298 *  - `ng-invalid`: the model is invalid
39299 *  - `ng-valid-[key]`: for each valid key added by `$setValidity`
39300 *  - `ng-invalid-[key]`: for each invalid key added by `$setValidity`
39301 *  - `ng-pristine`: the control hasn't been interacted with yet
39302 *  - `ng-dirty`: the control has been interacted with
39303 *  - `ng-touched`: the control has been blurred
39304 *  - `ng-untouched`: the control hasn't been blurred
39305 *  - `ng-pending`: any `$asyncValidators` are unfulfilled
39306 *  - `ng-empty`: the view does not contain a value or the value is deemed "empty", as defined
39307 *     by the {@link ngModel.NgModelController#$isEmpty} method
39308 *  - `ng-not-empty`: the view contains a non-empty value
39309 *
39310 * Keep in mind that ngAnimate can detect each of these classes when added and removed.
39311 *
39312 * ## Animation Hooks
39313 *
39314 * Animations within models are triggered when any of the associated CSS classes are added and removed
39315 * on the input element which is attached to the model. These classes include: `.ng-pristine`, `.ng-dirty`,
39316 * `.ng-invalid` and `.ng-valid` as well as any other validations that are performed on the model itself.
39317 * The animations that are triggered within ngModel are similar to how they work in ngClass and
39318 * animations can be hooked into using CSS transitions, keyframes as well as JS animations.
39319 *
39320 * The following example shows a simple way to utilize CSS transitions to style an input element
39321 * that has been rendered as invalid after it has been validated:
39322 *
39323 * <pre>
39324 * //be sure to include ngAnimate as a module to hook into more
39325 * //advanced animations
39326 * .my-input {
39327 *   transition:0.5s linear all;
39328 *   background: white;
39329 * }
39330 * .my-input.ng-invalid {
39331 *   background: red;
39332 *   color:white;
39333 * }
39334 * </pre>
39335 *
39336 * @example
39337 * <example deps="angular-animate.js" animations="true" fixBase="true" module="inputExample" name="ng-model">
39338     <file name="index.html">
39339       <script>
39340        angular.module('inputExample', [])
39341          .controller('ExampleController', ['$scope', function($scope) {
39342            $scope.val = '1';
39343          }]);
39344       </script>
39345       <style>
39346         .my-input {
39347           transition:all linear 0.5s;
39348           background: transparent;
39349         }
39350         .my-input.ng-invalid {
39351           color:white;
39352           background: red;
39353         }
39354       </style>
39355       <p id="inputDescription">
39356        Update input to see transitions when valid/invalid.
39357        Integer is a valid value.
39358       </p>
39359       <form name="testForm" ng-controller="ExampleController">
39360         <input ng-model="val" ng-pattern="/^\d+$/" name="anim" class="my-input"
39361                aria-describedby="inputDescription" />
39362       </form>
39363     </file>
39364 * </example>
39365 *
39366 * ## Binding to a getter/setter
39367 *
39368 * Sometimes it's helpful to bind `ngModel` to a getter/setter function.  A getter/setter is a
39369 * function that returns a representation of the model when called with zero arguments, and sets
39370 * the internal state of a model when called with an argument. It's sometimes useful to use this
39371 * for models that have an internal representation that's different from what the model exposes
39372 * to the view.
39373 *
39374 * <div class="alert alert-success">
39375 * **Best Practice:** It's best to keep getters fast because Angular is likely to call them more
39376 * frequently than other parts of your code.
39377 * </div>
39378 *
39379 * You use this behavior by adding `ng-model-options="{ getterSetter: true }"` to an element that
39380 * has `ng-model` attached to it. You can also add `ng-model-options="{ getterSetter: true }"` to
39381 * a `<form>`, which will enable this behavior for all `<input>`s within it. See
39382 * {@link ng.directive:ngModelOptions `ngModelOptions`} for more.
39383 *
39384 * The following example shows how to use `ngModel` with a getter/setter:
39385 *
39386 * @example
39387 * <example name="ngModel-getter-setter" module="getterSetterExample">
39388     <file name="index.html">
39389       <div ng-controller="ExampleController">
39390         <form name="userForm">
39391           <label>Name:
39392             <input type="text" name="userName"
39393                    ng-model="user.name"
39394                    ng-model-options="{ getterSetter: true }" />
39395           </label>
39396         </form>
39397         <pre>user.name = <span ng-bind="user.name()"></span></pre>
39398       </div>
39399     </file>
39400     <file name="app.js">
39401       angular.module('getterSetterExample', [])
39402         .controller('ExampleController', ['$scope', function($scope) {
39403           var _name = 'Brian';
39404           $scope.user = {
39405             name: function(newName) {
39406              // Note that newName can be undefined for two reasons:
39407              // 1. Because it is called as a getter and thus called with no arguments
39408              // 2. Because the property should actually be set to undefined. This happens e.g. if the
39409              //    input is invalid
39410              return arguments.length ? (_name = newName) : _name;
39411             }
39412           };
39413         }]);
39414     </file>
39415 * </example>
39416 */
39417var ngModelDirective = ['$rootScope', function($rootScope) {
39418  return {
39419    restrict: 'A',
39420    require: ['ngModel', '^?form', '^?ngModelOptions'],
39421    controller: NgModelController,
39422    // Prelink needs to run before any input directive
39423    // so that we can set the NgModelOptions in NgModelController
39424    // before anyone else uses it.
39425    priority: 1,
39426    compile: function ngModelCompile(element) {
39427      // Setup initial state of the control
39428      element.addClass(PRISTINE_CLASS).addClass(UNTOUCHED_CLASS).addClass(VALID_CLASS);
39429
39430      return {
39431        pre: function ngModelPreLink(scope, element, attr, ctrls) {
39432          var modelCtrl = ctrls[0],
39433              formCtrl = ctrls[1] || modelCtrl.$$parentForm,
39434              optionsCtrl = ctrls[2];
39435
39436          if (optionsCtrl) {
39437            modelCtrl.$options = optionsCtrl.$options;
39438          }
39439
39440          modelCtrl.$$initGetterSetters();
39441
39442          // notify others, especially parent forms
39443          formCtrl.$addControl(modelCtrl);
39444
39445          attr.$observe('name', function(newValue) {
39446            if (modelCtrl.$name !== newValue) {
39447              modelCtrl.$$parentForm.$$renameControl(modelCtrl, newValue);
39448            }
39449          });
39450
39451          scope.$on('$destroy', function() {
39452            modelCtrl.$$parentForm.$removeControl(modelCtrl);
39453          });
39454        },
39455        post: function ngModelPostLink(scope, element, attr, ctrls) {
39456          var modelCtrl = ctrls[0];
39457          if (modelCtrl.$options.getOption('updateOn')) {
39458            element.on(modelCtrl.$options.getOption('updateOn'), function(ev) {
39459              modelCtrl.$$debounceViewValueCommit(ev && ev.type);
39460            });
39461          }
39462
39463          function setTouched() {
39464            modelCtrl.$setTouched();
39465          }
39466
39467          element.on('blur', function() {
39468            if (modelCtrl.$touched) return;
39469
39470            if ($rootScope.$$phase) {
39471              scope.$evalAsync(setTouched);
39472            } else {
39473              scope.$apply(setTouched);
39474            }
39475          });
39476        }
39477      };
39478    }
39479  };
39480}];
39481
39482/* exported defaultModelOptions */
39483var defaultModelOptions;
39484var DEFAULT_REGEXP = /(\s+|^)default(\s+|$)/;
39485
39486/**
39487 * @ngdoc type
39488 * @name ModelOptions
39489 * @description
39490 * A container for the options set by the {@link ngModelOptions} directive
39491 */
39492function ModelOptions(options) {
39493  this.$$options = options;
39494}
39495
39496ModelOptions.prototype = {
39497
39498  /**
39499   * @ngdoc method
39500   * @name ModelOptions#getOption
39501   * @param {string} name the name of the option to retrieve
39502   * @returns {*} the value of the option
39503   * @description
39504   * Returns the value of the given option
39505   */
39506  getOption: function(name) {
39507    return this.$$options[name];
39508  },
39509
39510  /**
39511   * @ngdoc method
39512   * @name ModelOptions#createChild
39513   * @param {Object} options a hash of options for the new child that will override the parent's options
39514   * @return {ModelOptions} a new `ModelOptions` object initialized with the given options.
39515   */
39516  createChild: function(options) {
39517    var inheritAll = false;
39518
39519    // make a shallow copy
39520    options = extend({}, options);
39521
39522    // Inherit options from the parent if specified by the value `"$inherit"`
vendor: 5,565 bytes, lines 39523-39662
39523    forEach(options, /* @this */ function(option, key) {
39524      if (option === '$inherit') {
39525        if (key === '*') {
39526          inheritAll = true;
39527        } else {
39528          options[key] = this.$$options[key];
39529          // `updateOn` is special so we must also inherit the `updateOnDefault` option
39530          if (key === 'updateOn') {
39531            options.updateOnDefault = this.$$options.updateOnDefault;
39532          }
39533        }
39534      } else {
39535        if (key === 'updateOn') {
39536          // If the `updateOn` property contains the `default` event then we have to remove
39537          // it from the event list and set the `updateOnDefault` flag.
39538          options.updateOnDefault = false;
39539          options[key] = trim(option.replace(DEFAULT_REGEXP, function() {
39540            options.updateOnDefault = true;
39541            return ' ';
39542          }));
39543        }
39544      }
39545    }, this);
39546
39547    if (inheritAll) {
39548      // We have a property of the form: `"*": "$inherit"`
39549      delete options['*'];
39550      defaults(options, this.$$options);
39551    }
39552
39553    // Finally add in any missing defaults
39554    defaults(options, defaultModelOptions.$$options);
39555
39556    return new ModelOptions(options);
39557  }
39558};
39559
39560
39561defaultModelOptions = new ModelOptions({
39562  updateOn: '',
39563  updateOnDefault: true,
39564  debounce: 0,
39565  getterSetter: false,
39566  allowInvalid: false,
39567  timezone: null
39568});
39569
39570
39571/**
39572 * @ngdoc directive
39573 * @name ngModelOptions
39574 *
39575 * @description
39576 * This directive allows you to modify the behaviour of {@link ngModel} directives within your
39577 * application. You can specify an `ngModelOptions` directive on any element. All {@link ngModel}
39578 * directives will use the options of their nearest `ngModelOptions` ancestor.
39579 *
39580 * The `ngModelOptions` settings are found by evaluating the value of the attribute directive as
39581 * an Angular expression. This expression should evaluate to an object, whose properties contain
39582 * the settings. For example: `<div "ng-model-options"="{ debounce: 100 }"`.
39583 *
39584 * ## Inheriting Options
39585 *
39586 * You can specify that an `ngModelOptions` setting should be inherited from a parent `ngModelOptions`
39587 * directive by giving it the value of `"$inherit"`.
39588 * Then it will inherit that setting from the first `ngModelOptions` directive found by traversing up the
39589 * DOM tree. If there is no ancestor element containing an `ngModelOptions` directive then default settings
39590 * will be used.
39591 *
39592 * For example given the following fragment of HTML
39593 *
39594 *
39595 * ```html
39596 * <div ng-model-options="{ allowInvalid: true, debounce: 200 }">
39597 *   <form ng-model-options="{ updateOn: 'blur', allowInvalid: '$inherit' }">
39598 *     <input ng-model-options="{ updateOn: 'default', allowInvalid: '$inherit' }" />
39599 *   </form>
39600 * </div>
39601 * ```
39602 *
39603 * the `input` element will have the following settings
39604 *
39605 * ```js
39606 * { allowInvalid: true, updateOn: 'default', debounce: 0 }
39607 * ```
39608 *
39609 * Notice that the `debounce` setting was not inherited and used the default value instead.
39610 *
39611 * You can specify that all undefined settings are automatically inherited from an ancestor by
39612 * including a property with key of `"*"` and value of `"$inherit"`.
39613 *
39614 * For example given the following fragment of HTML
39615 *
39616 *
39617 * ```html
39618 * <div ng-model-options="{ allowInvalid: true, debounce: 200 }">
39619 *   <form ng-model-options="{ updateOn: 'blur', "*": '$inherit' }">
39620 *     <input ng-model-options="{ updateOn: 'default', "*": '$inherit' }" />
39621 *   </form>
39622 * </div>
39623 * ```
39624 *
39625 * the `input` element will have the following settings
39626 *
39627 * ```js
39628 * { allowInvalid: true, updateOn: 'default', debounce: 200 }
39629 * ```
39630 *
39631 * Notice that the `debounce` setting now inherits the value from the outer `<div>` element.
39632 *
39633 * If you are creating a reusable component then you should be careful when using `"*": "$inherit"`
39634 * since you may inadvertently inherit a setting in the future that changes the behavior of your component.
39635 *
39636 *
39637 * ## Triggering and debouncing model updates
39638 *
39639 * The `updateOn` and `debounce` properties allow you to specify a custom list of events that will
39640 * trigger a model update and/or a debouncing delay so that the actual update only takes place when
39641 * a timer expires; this timer will be reset after another change takes place.
39642 *
39643 * Given the nature of `ngModelOptions`, the value displayed inside input fields in the view might
39644 * be different from the value in the actual model. This means that if you update the model you
39645 * should also invoke {@link ngModel.NgModelController#$rollbackViewValue} on the relevant input field in
39646 * order to make sure it is synchronized with the model and that any debounced action is canceled.
39647 *
39648 * The easiest way to reference the control's {@link ngModel.NgModelController#$rollbackViewValue}
39649 * method is by making sure the input is placed inside a form that has a `name` attribute. This is
39650 * important because `form` controllers are published to the related scope under the name in their
39651 * `name` attribute.
39652 *
39653 * Any pending changes will take place immediately when an enclosing form is submitted via the
39654 * `submit` event. Note that `ngClick` events will occur before the model is updated. Use `ngSubmit`
39655 * to have access to the updated model.
39656 *
39657 * The following example shows how to override immediate updates. Changes on the inputs within the
39658 * form will update the model only when the control loses focus (blur event). If `escape` key is
39659 * pressed while the input field is focused, the value is reset to the value in the current model.
39660 *
39661 * <example name="ngModelOptions-directive-blur" module="optionsExample">
39662 *   <file name="index.html">
39663 *     <div ng-controller="ExampleController">
39664 *       <form name="userForm">
39665 *         <label>
39666 *           Name:
39667 *           <input type="text" name="userName"
39668 *                  ng-model="user.name"
39669 *                  ng-model-options="{ updateOn: 'blur' }"
39670 *                  ng-keyup="cancel($event)" />
39671 *         </label><br />
39672 *         <label>
39673 *           Other data:
39674 *           <input type="text" ng-model="user.data" />
39675 *         </label><br />
39676 *       </form>
39677 *       <pre>user.name = <span ng-bind="user.name"></span></pre>
39678 *     </div>
39679 *   </file>
39680 *   <file name="app.js">
39681 *     angular.module('optionsExample', [])
39682 *       .controller('ExampleController', ['$scope', function($scope) {
39683 *         $scope.user = { name: 'say', data: '' };
39684 *
39685 *         $scope.cancel = function(e) {
39686 *           if (e.keyCode === 27) {
39687 *             $scope.userForm.userName.$rollbackViewValue();
39688 *           }
39689 *         };
39690 *       }]);
39691 *   </file>
39692 *   <file name="protractor.js" type="protractor">
39693 *     var model = element(by.binding('user.name'));
39694 *     var input = element(by.model('user.name'));
39695 *     var other = element(by.model('user.data'));
39696 *
39697 *     it('should allow custom events', function() {
39698 *       input.sendKeys(' hello');
39699 *       input.click();
39700 *       expect(model.getText()).toEqual('say');
39701 *       other.click();
39702 *       expect(model.getText()).toEqual('say hello');
39703 *     });
39704 *
39705 *     it('should $rollbackViewValue when model changes', function() {
39706 *       input.sendKeys(' hello');
39707 *       expect(input.getAttribute('value')).toEqual('say hello');
39708 *       input.sendKeys(protractor.Key.ESCAPE);
39709 *       expect(input.getAttribute('value')).toEqual('say');
39710 *       other.click();
39711 *       expect(model.getText()).toEqual('say');
39712 *     });
39713 *   </file>
39714 * </example>
39715 *
39716 * The next example shows how to debounce model changes. Model will be updated only 1 sec after last change.
39717 * If the `Clear` button is pressed, any debounced action is canceled and the value becomes empty.
39718 *
39719 * <example name="ngModelOptions-directive-debounce" module="optionsExample">
39720 *   <file name="index.html">
39721 *     <div ng-controller="ExampleController">
39722 *       <form name="userForm">
39723 *         Name:
39724 *         <input type="text" name="userName"
39725 *                ng-model="user.name"
39726 *                ng-model-options="{ debounce: 1000 }" />
39727 *         <button ng-click="userForm.userName.$rollbackViewValue(); user.name=''">Clear</button><br />
39728 *       </form>
39729 *       <pre>user.name = <span ng-bind="user.name"></span></pre>
39730 *     </div>
39731 *   </file>
39732 *   <file name="app.js">
39733 *     angular.module('optionsExample', [])
39734 *       .controller('ExampleController', ['$scope', function($scope) {
39735 *         $scope.user = { name: 'say' };
39736 *       }]);
39737 *   </file>
39738 * </example>
39739 *
39740 * ## Model updates and validation
39741 *
39742 * The default behaviour in `ngModel` is that the model value is set to `undefined` when the
39743 * validation determines that the value is invalid. By setting the `allowInvalid` property to true,
39744 * the model will still be updated even if the value is invalid.
39745 *
39746 *
39747 * ## Connecting to the scope
39748 *
39749 * By setting the `getterSetter` property to true you are telling ngModel that the `ngModel` expression
39750 * on the scope refers to a "getter/setter" function rather than the value itself.
39751 *
39752 * The following example shows how to bind to getter/setters:
39753 *
39754 * <example name="ngModelOptions-directive-getter-setter" module="getterSetterExample">
39755 *   <file name="index.html">
39756 *     <div ng-controller="ExampleController">
39757 *       <form name="userForm">
39758 *         <label>
39759 *           Name:
39760 *           <input type="text" name="userName"
39761 *                  ng-model="user.name"
39762 *                  ng-model-options="{ getterSetter: true }" />
39763 *         </label>
39764 *       </form>
39765 *       <pre>user.name = <span ng-bind="user.name()"></span></pre>
39766 *     </div>
39767 *   </file>
39768 *   <file name="app.js">
39769 *     angular.module('getterSetterExample', [])
39770 *       .controller('ExampleController', ['$scope', function($scope) {
39771 *         var _name = 'Brian';
39772 *         $scope.user = {
39773 *           name: function(newName) {
39774 *             return angular.isDefined(newName) ? (_name = newName) : _name;
39775 *           }
39776 *         };
39777 *       }]);
39778 *   </file>
39779 * </example>
39780 *
39781 *
39782 * ## Specifying timezones
39783 *
39784 * You can specify the timezone that date/time input directives expect by providing its name in the
39785 * `timezone` property.
39786 *
39787 * @param {Object} ngModelOptions options to apply to {@link ngModel} directives on this element and
39788 *   and its descendents. Valid keys are:
39789 *   - `updateOn`: string specifying which event should the input be bound to. You can set several
39790 *     events using an space delimited list. There is a special event called `default` that
39791 *     matches the default events belonging to the control.
39792 *   - `debounce`: integer value which contains the debounce model update value in milliseconds. A
39793 *     value of 0 triggers an immediate update. If an object is supplied instead, you can specify a
39794 *     custom value for each event. For example:
39795 *     ```
39796 *     ng-model-options="{
39797 *       updateOn: 'default blur',
39798 *       debounce: { 'default': 500, 'blur': 0 }
39799 *     }"
39800 *     ```
39801 *   - `allowInvalid`: boolean value which indicates that the model can be set with values that did
39802 *     not validate correctly instead of the default behavior of setting the model to undefined.
39803 *   - `getterSetter`: boolean value which determines whether or not to treat functions bound to
39804 *     `ngModel` as getters/setters.
39805 *   - `timezone`: Defines the timezone to be used to read/write the `Date` instance in the model for
39806 *     `<input type="date" />`, `<input type="time" />`, ... . It understands UTC/GMT and the
39807 *     continental US time zone abbreviations, but for general use, use a time zone offset, for
39808 *     example, `'+0430'` (4 hours, 30 minutes east of the Greenwich meridian)
39809 *     If not specified, the timezone of the browser will be used.
39810 *
39811 */
39812var ngModelOptionsDirective = function() {
39813  NgModelOptionsController.$inject = ['$attrs', '$scope'];
39814  function NgModelOptionsController($attrs, $scope) {
39815    this.$$attrs = $attrs;
39816    this.$$scope = $scope;
39817  }
39818  NgModelOptionsController.prototype = {
39819    $onInit: function() {
39820      var parentOptions = this.parentCtrl ? this.parentCtrl.$options : defaultModelOptions;
39821      var modelOptionsDefinition = this.$$scope.$eval(this.$$attrs.ngModelOptions);
39822
39823      this.$options = parentOptions.createChild(modelOptionsDefinition);
39824    }
39825  };
39826
39827  return {
39828    restrict: 'A',
39829    // ngModelOptions needs to run before ngModel and input directives
39830    priority: 10,
39831    require: {parentCtrl: '?^^ngModelOptions'},
39832    bindToController: true,
39833    controller: NgModelOptionsController
39834  };
39835};
39836
39837
39838// shallow copy over values from `src` that are not already specified on `dst`
39839function defaults(dst, src) {
39840  forEach(src, function(value, key) {
39841    if (!isDefined(dst[key])) {
39842      dst[key] = value;
39843    }
39844  });
39845}
39846
39847/**
39848 * @ngdoc directive
39849 * @name ngNonBindable
39850 * @restrict AC
39851 * @priority 1000
39852 *
39853 * @description
39854 * The `ngNonBindable` directive tells Angular not to compile or bind the contents of the current
39855 * DOM element. This is useful if the element contains what appears to be Angular directives and
39856 * bindings but which should be ignored by Angular. This could be the case if you have a site that
39857 * displays snippets of code, for instance.
39858 *
39859 * @element ANY
39860 *
39861 * @example
39862 * In this example there are two locations where a simple interpolation binding (`{{}}`) is present,
39863 * but the one wrapped in `ngNonBindable` is left alone.
39864 *
39865 * @example
39866    <example name="ng-non-bindable">
39867      <file name="index.html">
39868        <div>Normal: {{1 + 2}}</div>
39869        <div ng-non-bindable>Ignored: {{1 + 2}}</div>
39870      </file>
39871      <file name="protractor.js" type="protractor">
39872       it('should check ng-non-bindable', function() {
39873         expect(element(by.binding('1 + 2')).getText()).toContain('3');
39874         expect(element.all(by.css('div')).last().getText()).toMatch(/1 \+ 2/);
39875       });
39876      </file>
39877  
vendor: 18,942 bytes, lines 39877-40288
39877  </example>
39878 */
39879var ngNonBindableDirective = ngDirective({ terminal: true, priority: 1000 });
39880
39881/* exported ngOptionsDirective */
39882
39883/* global jqLiteRemove */
39884
39885var ngOptionsMinErr = minErr('ngOptions');
39886
39887/**
39888 * @ngdoc directive
39889 * @name ngOptions
39890 * @restrict A
39891 *
39892 * @description
39893 *
39894 * The `ngOptions` attribute can be used to dynamically generate a list of `<option>`
39895 * elements for the `<select>` element using the array or object obtained by evaluating the
39896 * `ngOptions` comprehension expression.
39897 *
39898 * In many cases, {@link ng.directive:ngRepeat ngRepeat} can be used on `<option>` elements instead of
39899 * `ngOptions` to achieve a similar result. However, `ngOptions` provides some benefits:
39900 * - more flexibility in how the `<select>`'s model is assigned via the `select` **`as`** part of the
39901 * comprehension expression
39902 * - reduced memory consumption by not creating a new scope for each repeated instance
39903 * - increased render speed by creating the options in a documentFragment instead of individually
39904 *
39905 * When an item in the `<select>` menu is selected, the array element or object property
39906 * represented by the selected option will be bound to the model identified by the `ngModel`
39907 * directive.
39908 *
39909 * Optionally, a single hard-coded `<option>` element, with the value set to an empty string, can
39910 * be nested into the `<select>` element. This element will then represent the `null` or "not selected"
39911 * option. See example below for demonstration.
39912 *
39913 * ## Complex Models (objects or collections)
39914 *
39915 * By default, `ngModel` watches the model by reference, not value. This is important to know when
39916 * binding the select to a model that is an object or a collection.
39917 *
39918 * One issue occurs if you want to preselect an option. For example, if you set
39919 * the model to an object that is equal to an object in your collection, `ngOptions` won't be able to set the selection,
39920 * because the objects are not identical. So by default, you should always reference the item in your collection
39921 * for preselections, e.g.: `$scope.selected = $scope.collection[3]`.
39922 *
39923 * Another solution is to use a `track by` clause, because then `ngOptions` will track the identity
39924 * of the item not by reference, but by the result of the `track by` expression. For example, if your
39925 * collection items have an id property, you would `track by item.id`.
39926 *
39927 * A different issue with objects or collections is that ngModel won't detect if an object property or
39928 * a collection item changes. For that reason, `ngOptions` additionally watches the model using
39929 * `$watchCollection`, when the expression contains a `track by` clause or the the select has the `multiple` attribute.
39930 * This allows ngOptions to trigger a re-rendering of the options even if the actual object/collection
39931 * has not changed identity, but only a property on the object or an item in the collection changes.
39932 *
39933 * Note that `$watchCollection` does a shallow comparison of the properties of the object (or the items in the collection
39934 * if the model is an array). This means that changing a property deeper than the first level inside the
39935 * object/collection will not trigger a re-rendering.
39936 *
39937 * ## `select` **`as`**
39938 *
39939 * Using `select` **`as`** will bind the result of the `select` expression to the model, but
39940 * the value of the `<select>` and `<option>` html elements will be either the index (for array data sources)
39941 * or property name (for object data sources) of the value within the collection. If a **`track by`** expression
39942 * is used, the result of that expression will be set as the value of the `option` and `select` elements.
39943 *
39944 *
39945 * ### `select` **`as`** and **`track by`**
39946 *
39947 * <div class="alert alert-warning">
39948 * Be careful when using `select` **`as`** and **`track by`** in the same expression.
39949 * </div>
39950 *
39951 * Given this array of items on the $scope:
39952 *
39953 * ```js
39954 * $scope.items = [{
39955 *   id: 1,
39956 *   label: 'aLabel',
39957 *   subItem: { name: 'aSubItem' }
39958 * }, {
39959 *   id: 2,
39960 *   label: 'bLabel',
39961 *   subItem: { name: 'bSubItem' }
39962 * }];
39963 * ```
39964 *
39965 * This will work:
39966 *
39967 * ```html
39968 * <select ng-options="item as item.label for item in items track by item.id" ng-model="selected"></select>
39969 * ```
39970 * ```js
39971 * $scope.selected = $scope.items[0];
39972 * ```
39973 *
39974 * but this will not work:
39975 *
39976 * ```html
39977 * <select ng-options="item.subItem as item.label for item in items track by item.id" ng-model="selected"></select>
39978 * ```
39979 * ```js
39980 * $scope.selected = $scope.items[0].subItem;
39981 * ```
39982 *
39983 * In both examples, the **`track by`** expression is applied successfully to each `item` in the
39984 * `items` array. Because the selected option has been set programmatically in the controller, the
39985 * **`track by`** expression is also applied to the `ngModel` value. In the first example, the
39986 * `ngModel` value is `items[0]` and the **`track by`** expression evaluates to `items[0].id` with
39987 * no issue. In the second example, the `ngModel` value is `items[0].subItem` and the **`track by`**
39988 * expression evaluates to `items[0].subItem.id` (which is undefined). As a result, the model value
39989 * is not matched against any `<option>` and the `<select>` appears as having no selected value.
39990 *
39991 *
39992 * @param {string} ngModel Assignable AngularJS expression to data-bind to.
39993 * @param {comprehension_expression} ngOptions in one of the following forms:
39994 *
39995 *   * for array data sources:
39996 *     * `label` **`for`** `value` **`in`** `array`
39997 *     * `select` **`as`** `label` **`for`** `value` **`in`** `array`
39998 *     * `label` **`group by`** `group` **`for`** `value` **`in`** `array`
39999 *     * `label` **`disable when`** `disable` **`for`** `value` **`in`** `array`
40000 *     * `label` **`group by`** `group` **`for`** `value` **`in`** `array` **`track by`** `trackexpr`
40001 *     * `label` **`disable when`** `disable` **`for`** `value` **`in`** `array` **`track by`** `trackexpr`
40002 *     * `label` **`for`** `value` **`in`** `array` | orderBy:`orderexpr` **`track by`** `trackexpr`
40003 *        (for including a filter with `track by`)
40004 *   * for object data sources:
40005 *     * `label` **`for (`**`key` **`,`** `value`**`) in`** `object`
40006 *     * `select` **`as`** `label` **`for (`**`key` **`,`** `value`**`) in`** `object`
40007 *     * `label` **`group by`** `group` **`for (`**`key`**`,`** `value`**`) in`** `object`
40008 *     * `label` **`disable when`** `disable` **`for (`**`key`**`,`** `value`**`) in`** `object`
40009 *     * `select` **`as`** `label` **`group by`** `group`
40010 *         **`for` `(`**`key`**`,`** `value`**`) in`** `object`
40011 *     * `select` **`as`** `label` **`disable when`** `disable`
40012 *         **`for` `(`**`key`**`,`** `value`**`) in`** `object`
40013 *
40014 * Where:
40015 *
40016 *   * `array` / `object`: an expression which evaluates to an array / object to iterate over.
40017 *   * `value`: local variable which will refer to each item in the `array` or each property value
40018 *      of `object` during iteration.
40019 *   * `key`: local variable which will refer to a property name in `object` during iteration.
40020 *   * `label`: The result of this expression will be the label for `<option>` element. The
40021 *     `expression` will most likely refer to the `value` variable (e.g. `value.propertyName`).
40022 *   * `select`: The result of this expression will be bound to the model of the parent `<select>`
40023 *      element. If not specified, `select` expression will default to `value`.
40024 *   * `group`: The result of this expression will be used to group options using the `<optgroup>`
40025 *      DOM element.
40026 *   * `disable`: The result of this expression will be used to disable the rendered `<option>`
40027 *      element. Return `true` to disable.
40028 *   * `trackexpr`: Used when working with an array of objects. The result of this expression will be
40029 *      used to identify the objects in the array. The `trackexpr` will most likely refer to the
40030 *     `value` variable (e.g. `value.propertyName`). With this the selection is preserved
40031 *      even when the options are recreated (e.g. reloaded from the server).
40032 * @param {string=} name Property name of the form under which the control is published.
40033 * @param {string=} required The control is considered valid only if value is entered.
40034 * @param {string=} ngRequired Adds `required` attribute and `required` validation constraint to
40035 *    the element when the ngRequired expression evaluates to true. Use `ngRequired` instead of
40036 *    `required` when you want to data-bind to the `required` attribute.
40037 * @param {string=} ngAttrSize sets the size of the select element dynamically. Uses the
40038 * {@link guide/interpolation#-ngattr-for-binding-to-arbitrary-attributes ngAttr} directive.
40039 *
40040 * @example
40041    <example module="selectExample" name="select">
40042      <file name="index.html">
40043        <script>
40044        angular.module('selectExample', [])
40045          .controller('ExampleController', ['$scope', function($scope) {
40046            $scope.colors = [
40047              {name:'black', shade:'dark'},
40048              {name:'white', shade:'light', notAnOption: true},
40049              {name:'red', shade:'dark'},
40050              {name:'blue', shade:'dark', notAnOption: true},
40051              {name:'yellow', shade:'light', notAnOption: false}
40052            ];
40053            $scope.myColor = $scope.colors[2]; // red
40054          }]);
40055        </script>
40056        <div ng-controller="ExampleController">
40057          <ul>
40058            <li ng-repeat="color in colors">
40059              <label>Name: <input ng-model="color.name"></label>
40060              <label><input type="checkbox" ng-model="color.notAnOption"> Disabled?</label>
40061              <button ng-click="colors.splice($index, 1)" aria-label="Remove">X</button>
40062            </li>
40063            <li>
40064              <button ng-click="colors.push({})">add</button>
40065            </li>
40066          </ul>
40067          <hr/>
40068          <label>Color (null not allowed):
40069            <select ng-model="myColor" ng-options="color.name for color in colors"></select>
40070          </label><br/>
40071          <label>Color (null allowed):
40072          <span  class="nullable">
40073            <select ng-model="myColor" ng-options="color.name for color in colors">
40074              <option value="">-- choose color --</option>
40075            </select>
40076          </span></label><br/>
40077
40078          <label>Color grouped by shade:
40079            <select ng-model="myColor" ng-options="color.name group by color.shade for color in colors">
40080            </select>
40081          </label><br/>
40082
40083          <label>Color grouped by shade, with some disabled:
40084            <select ng-model="myColor"
40085                  ng-options="color.name group by color.shade disable when color.notAnOption for color in colors">
40086            </select>
40087          </label><br/>
40088
40089
40090
40091          Select <button ng-click="myColor = { name:'not in list', shade: 'other' }">bogus</button>.
40092          <br/>
40093          <hr/>
40094          Currently selected: {{ {selected_color:myColor} }}
40095          <div style="border:solid 1px black; height:20px"
40096               ng-style="{'background-color':myColor.name}">
40097          </div>
40098        </div>
40099      </file>
40100      <file name="protractor.js" type="protractor">
40101         it('should check ng-options', function() {
40102           expect(element(by.binding('{selected_color:myColor}')).getText()).toMatch('red');
40103           element.all(by.model('myColor')).first().click();
40104           element.all(by.css('select[ng-model="myColor"] option')).first().click();
40105           expect(element(by.binding('{selected_color:myColor}')).getText()).toMatch('black');
40106           element(by.css('.nullable select[ng-model="myColor"]')).click();
40107           element.all(by.css('.nullable select[ng-model="myColor"] option')).first().click();
40108           expect(element(by.binding('{selected_color:myColor}')).getText()).toMatch('null');
40109         });
40110      </file>
40111    </example>
40112 */
40113
40114/* eslint-disable max-len */
40115//                     //00001111111111000000000002222222222000000000000000000000333333333300000000000000000000000004444444444400000000000005555555555555000000000666666666666600000007777777777777000000000000000888888888800000000000000000009999999999
40116var 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]+?))?$/;
40117                        // 1: value expression (valueFn)
40118                        // 2: label expression (displayFn)
40119                        // 3: group by expression (groupByFn)
40120                        // 4: disable when expression (disableWhenFn)
40121                        // 5: array item variable name
40122                        // 6: object item key variable name
40123                        // 7: object item value variable name
40124                        // 8: collection expression
40125                        // 9: track by expression
40126/* eslint-enable */
40127
40128
40129var ngOptionsDirective = ['$compile', '$document', '$parse', function($compile, $document, $parse) {
40130
40131  function parseOptionsExpression(optionsExp, selectElement, scope) {
40132
40133    var match = optionsExp.match(NG_OPTIONS_REGEXP);
40134    if (!(match)) {
40135      throw ngOptionsMinErr('iexp',
40136        'Expected expression in form of ' +
40137        '\'_select_ (as _label_)? for (_key_,)?_value_ in _collection_\'' +
40138        ' but got \'{0}\'. Element: {1}',
40139        optionsExp, startingTag(selectElement));
40140    }
40141
40142    // Extract the parts from the ngOptions expression
40143
40144    // The variable name for the value of the item in the collection
40145    var valueName = match[5] || match[7];
40146    // The variable name for the key of the item in the collection
40147    var keyName = match[6];
40148
40149    // An expression that generates the viewValue for an option if there is a label expression
40150    var selectAs = / as /.test(match[0]) && match[1];
40151    // An expression that is used to track the id of each object in the options collection
40152    var trackBy = match[9];
40153    // An expression that generates the viewValue for an option if there is no label expression
40154    var valueFn = $parse(match[2] ? match[1] : valueName);
40155    var selectAsFn = selectAs && $parse(selectAs);
40156    var viewValueFn = selectAsFn || valueFn;
40157    var trackByFn = trackBy && $parse(trackBy);
40158
40159    // Get the value by which we are going to track the option
40160    // if we have a trackFn then use that (passing scope and locals)
40161    // otherwise just hash the given viewValue
40162    var getTrackByValueFn = trackBy ?
40163                              function(value, locals) { return trackByFn(scope, locals); } :
40164                              function getHashOfValue(value) { return hashKey(value); };
40165    var getTrackByValue = function(value, key) {
40166      return getTrackByValueFn(value, getLocals(value, key));
40167    };
40168
40169    var displayFn = $parse(match[2] || match[1]);
40170    var groupByFn = $parse(match[3] || '');
40171    var disableWhenFn = $parse(match[4] || '');
40172    var valuesFn = $parse(match[8]);
40173
40174    var locals = {};
40175    var getLocals = keyName ? function(value, key) {
40176      locals[keyName] = key;
40177      locals[valueName] = value;
40178      return locals;
40179    } : function(value) {
40180      locals[valueName] = value;
40181      return locals;
40182    };
40183
40184
40185    function Option(selectValue, viewValue, label, group, disabled) {
40186      this.selectValue = selectValue;
40187      this.viewValue = viewValue;
40188      this.label = label;
40189      this.group = group;
40190      this.disabled = disabled;
40191    }
40192
40193    function getOptionValuesKeys(optionValues) {
40194      var optionValuesKeys;
40195
40196      if (!keyName && isArrayLike(optionValues)) {
40197        optionValuesKeys = optionValues;
40198      } else {
40199        // if object, extract keys, in enumeration order, unsorted
40200        optionValuesKeys = [];
40201        for (var itemKey in optionValues) {
40202          if (optionValues.hasOwnProperty(itemKey) && itemKey.charAt(0) !== '$') {
40203            optionValuesKeys.push(itemKey);
40204          }
40205        }
40206      }
40207      return optionValuesKeys;
40208    }
40209
40210    return {
40211      trackBy: trackBy,
40212      getTrackByValue: getTrackByValue,
40213      getWatchables: $parse(valuesFn, function(optionValues) {
40214        // Create a collection of things that we would like to watch (watchedArray)
40215        // so that they can all be watched using a single $watchCollection
40216        // that only runs the handler once if anything changes
40217        var watchedArray = [];
40218        optionValues = optionValues || [];
40219
40220        var optionValuesKeys = getOptionValuesKeys(optionValues);
40221        var optionValuesLength = optionValuesKeys.length;
40222        for (var index = 0; index < optionValuesLength; index++) {
40223          var key = (optionValues === optionValuesKeys) ? index : optionValuesKeys[index];
40224          var value = optionValues[key];
40225
40226          var locals = getLocals(value, key);
40227          var selectValue = getTrackByValueFn(value, locals);
40228          watchedArray.push(selectValue);
40229
40230          // Only need to watch the displayFn if there is a specific label expression
40231          if (match[2] || match[1]) {
40232            var label = displayFn(scope, locals);
40233            watchedArray.push(label);
40234          }
40235
40236          // Only need to watch the disableWhenFn if there is a specific disable expression
40237          if (match[4]) {
40238            var disableWhen = disableWhenFn(scope, locals);
40239            watchedArray.push(disableWhen);
40240          }
40241        }
40242        return watchedArray;
40243      }),
40244
40245      getOptions: function() {
40246
40247        var optionItems = [];
40248        var selectValueMap = {};
40249
40250        // The option values were already computed in the `getWatchables` fn,
40251        // which must have been called to trigger `getOptions`
40252        var optionValues = valuesFn(scope) || [];
40253        var optionValuesKeys = getOptionValuesKeys(optionValues);
40254        var optionValuesLength = optionValuesKeys.length;
40255
40256        for (var index = 0; index < optionValuesLength; index++) {
40257          var key = (optionValues === optionValuesKeys) ? index : optionValuesKeys[index];
40258          var value = optionValues[key];
40259          var locals = getLocals(value, key);
40260          var viewValue = viewValueFn(scope, locals);
40261          var selectValue = getTrackByValueFn(viewValue, locals);
40262          var label = displayFn(scope, locals);
40263          var group = groupByFn(scope, locals);
40264          var disabled = disableWhenFn(scope, locals);
40265          var optionItem = new Option(selectValue, viewValue, label, group, disabled);
40266
40267          optionItems.push(optionItem);
40268          selectValueMap[selectValue] = optionItem;
40269        }
40270
40271        return {
40272          items: optionItems,
40273          selectValueMap: selectValueMap,
40274          getOptionFromViewValue: function(value) {
40275            return selectValueMap[getTrackByValue(value)];
40276          },
40277          getViewValueFromOption: function(option) {
40278            // If the viewValue could be an object that may be mutated by the application,
40279            // we need to make a copy and not return the reference to the value on the option.
40280            return trackBy ? copy(option.viewValue) : option.viewValue;
40281          }
40282        };
40283      }
40284    };
40285  }
40286
40287
40288  // 
40288we can't just jqLite('<option>') since jqLite is not smart enough
40289  // to create it in <select> and IE barfs otherwise.
40290  var optionTemplate = window.document.createElement('option'),
40291      optGroupTemplate = window.document.createElement('optgroup');
40292
40293    function ngOptionsPostLink(scope, selectElement, attr, ctrls) {
40294
40295      var selectCtrl = ctrls[0];
40296      var ngModelCtrl = ctrls[1];
40297      var multiple = attr.multiple;
40298
40299      // The emptyOption allows the application developer to provide their own custom "empty"
40300      // option when the viewValue does not match any of the option values.
40301      for (var i = 0, children = selectElement.children(), ii = children.length; i < ii; i++) {
40302        if (children[i].value === '') {
40303          selectCtrl.hasEmptyOption = true;
40304          selectCtrl.emptyOption = children.eq(i);
40305          break;
40306        }
40307      }
40308
40309      var providedEmptyOption = !!selectCtrl.emptyOption;
40310
40311      var unknownOption = jqLite(optionTemplate.cloneNode(false));
40312      unknownOption.val('?');
40313
40314      var options;
40315      var ngOptions = parseOptionsExpression(attr.ngOptions, selectElement, scope);
40316      // This stores the newly created options before they are appended to the select.
40317      // Since the contents are removed from the fragment when it is appended,
40318      // we only need to create it once.
40319      var listFragment = $document[0].createDocumentFragment();
40320
40321      // Overwrite the implementation. ngOptions doesn't use hashes
40322      selectCtrl.generateUnknownOptionValue = function(val) {
40323        return '?';
40324      };
40325
40326      // Update the controller methods for multiple selectable options
40327      if (!multiple) {
40328
40329        selectCtrl.writeValue = function writeNgOptionsValue(value) {
40330          var selectedOption = options.selectValueMap[selectElement.val()];
40331          var option = options.getOptionFromViewValue(value);
40332
40333          // Make sure to remove the selected attribute from the previously selected option
40334          // Otherwise, screen readers might get confused
40335          if (selectedOption) selectedOption.element.removeAttribute('selected');
40336
40337          if (option) {
40338            // Don't update the option when it is already selected.
40339            // For example, the browser will select the first option by default. In that case,
40340            // most properties are set automatically - except the `selected` attribute, which we
40341            // set always
40342
40343            if (selectElement[0].value !== option.selectValue) {
40344              selectCtrl.removeUnknownOption();
40345              selectCtrl.unselectEmptyOption();
40346
40347              selectElement[0].value = option.selectValue;
40348              option.element.selected = true;
40349            }
40350
40351            option.element.setAttribute('selected', 'selected');
40352          } else {
40353
40354            if (providedEmptyOption) {
40355              selectCtrl.selectEmptyOption();
40356            } else if (selectCtrl.unknownOption.parent().length) {
40357              selectCtrl.updateUnknownOption(value);
40358            } else {
40359              selectCtrl.renderUnknownOption(value);
40360            }
40361          }
40362        };
40363
40364        selectCtrl.readValue = function readNgOptionsValue() {
40365
40366          var selectedOption = options.selectValueMap[selectElement.val()];
40367
40368          if (selectedOption && !selectedOption.disabled) {
40369            selectCtrl.unselectEmptyOption();
40370            selectCtrl.removeUnknownOption();
40371            return options.getViewValueFromOption(selectedOption);
40372          }
40373          return null;
40374        };
40375
40376        // If we are using `track by` then we must watch the tracked value on the model
40377        // since ngModel only watches for object identity change
vendor: 10,731 bytes, lines 40378-40656
40378        // FIXME: When a user selects an option, this watch will fire needlessly
40379        if (ngOptions.trackBy) {
40380          scope.$watch(
40381            function() { return ngOptions.getTrackByValue(ngModelCtrl.$viewValue); },
40382            function() { ngModelCtrl.$render(); }
40383          );
40384        }
40385
40386      } else {
40387
40388        selectCtrl.writeValue = function writeNgOptionsMultiple(values) {
40389          // Only set `<option>.selected` if necessary, in order to prevent some browsers from
40390          // scrolling to `<option>` elements that are outside the `<select>` element's viewport.
40391
40392          var selectedOptions = values && values.map(getAndUpdateSelectedOption) || [];
40393
40394          options.items.forEach(function(option) {
40395            if (option.element.selected && !includes(selectedOptions, option)) {
40396              option.element.selected = false;
40397            }
40398          });
40399        };
40400
40401
40402        selectCtrl.readValue = function readNgOptionsMultiple() {
40403          var selectedValues = selectElement.val() || [],
40404              selections = [];
40405
40406          forEach(selectedValues, function(value) {
40407            var option = options.selectValueMap[value];
40408            if (option && !option.disabled) selections.push(options.getViewValueFromOption(option));
40409          });
40410
40411          return selections;
40412        };
40413
40414        // If we are using `track by` then we must watch these tracked values on the model
40415        // since ngModel only watches for object identity change
40416        if (ngOptions.trackBy) {
40417
40418          scope.$watchCollection(function() {
40419            if (isArray(ngModelCtrl.$viewValue)) {
40420              return ngModelCtrl.$viewValue.map(function(value) {
40421                return ngOptions.getTrackByValue(value);
40422              });
40423            }
40424          }, function() {
40425            ngModelCtrl.$render();
40426          });
40427
40428        }
40429      }
40430
40431      if (providedEmptyOption) {
40432
40433        // we need to remove it before calling selectElement.empty() because otherwise IE will
40434        // remove the label from the element. wtf?
40435        selectCtrl.emptyOption.remove();
40436
40437        // compile the element since there might be bindings in it
40438        $compile(selectCtrl.emptyOption)(scope);
40439
40440        if (selectCtrl.emptyOption[0].nodeType === NODE_TYPE_COMMENT) {
40441          // This means the empty option has currently no actual DOM node, probably because
40442          // it has been modified by a transclusion directive.
40443          selectCtrl.hasEmptyOption = false;
40444
40445          // Redefine the registerOption function, which will catch
40446          // options that are added by ngIf etc. (rendering of the node is async because of
40447          // lazy transclusion)
40448          selectCtrl.registerOption = function(optionScope, optionEl) {
40449            if (optionEl.val() === '') {
40450              selectCtrl.hasEmptyOption = true;
40451              selectCtrl.emptyOption = optionEl;
40452              selectCtrl.emptyOption.removeClass('ng-scope');
40453              // This ensures the new empty option is selected if previously no option was selected
40454              ngModelCtrl.$render();
40455
40456              optionEl.on('$destroy', function() {
40457                selectCtrl.hasEmptyOption = false;
40458                selectCtrl.emptyOption = undefined;
40459              });
40460            }
40461          };
40462
40463        } else {
40464          // remove the class, which is added automatically because we recompile the element and it
40465          // becomes the compilation root
40466          selectCtrl.emptyOption.removeClass('ng-scope');
40467        }
40468
40469      }
40470
40471      selectElement.empty();
40472
40473      // We need to do this here to ensure that the options object is defined
40474      // when we first hit it in writeNgOptionsValue
40475      updateOptions();
40476
40477      // We will re-render the option elements if the option values or labels change
40478      scope.$watchCollection(ngOptions.getWatchables, updateOptions);
40479
40480      // ------------------------------------------------------------------ //
40481
40482      function addOptionElement(option, parent) {
40483        var optionElement = optionTemplate.cloneNode(false);
40484        parent.appendChild(optionElement);
40485        updateOptionElement(option, optionElement);
40486      }
40487
40488      function getAndUpdateSelectedOption(viewValue) {
40489        var option = options.getOptionFromViewValue(viewValue);
40490        var element = option && option.element;
40491
40492        if (element && !element.selected) element.selected = true;
40493
40494        return option;
40495      }
40496
40497      function updateOptionElement(option, element) {
40498        option.element = element;
40499        element.disabled = option.disabled;
40500        // NOTE: The label must be set before the value, otherwise IE10/11/EDGE create unresponsive
40501        // selects in certain circumstances when multiple selects are next to each other and display
40502        // the option list in listbox style, i.e. the select is [multiple], or specifies a [size].
40503        // See https://github.com/angular/angular.js/issues/11314 for more info.
40504        // This is unfortunately untestable with unit / e2e tests
40505        if (option.label !== element.label) {
40506          element.label = option.label;
40507          element.textContent = option.label;
40508        }
40509        element.value = option.selectValue;
40510      }
40511
40512      function updateOptions() {
40513        var previousValue = options && selectCtrl.readValue();
40514
40515        // We must remove all current options, but cannot simply set innerHTML = null
40516        // since the providedEmptyOption might have an ngIf on it that inserts comments which we
40517        // must preserve.
40518        // Instead, iterate over the current option elements and remove them or their optgroup
40519        // parents
40520        if (options) {
40521
40522          for (var i = options.items.length - 1; i >= 0; i--) {
40523            var option = options.items[i];
40524            if (isDefined(option.group)) {
40525              jqLiteRemove(option.element.parentNode);
40526            } else {
40527              jqLiteRemove(option.element);
40528            }
40529          }
40530        }
40531
40532        options = ngOptions.getOptions();
40533
40534        var groupElementMap = {};
40535
40536        // Ensure that the empty option is always there if it was explicitly provided
40537        if (providedEmptyOption) {
40538          selectElement.prepend(selectCtrl.emptyOption);
40539        }
40540
40541        options.items.forEach(function addOption(option) {
40542          var groupElement;
40543
40544          if (isDefined(option.group)) {
40545
40546            // This option is to live in a group
40547            // See if we have already created this group
40548            groupElement = groupElementMap[option.group];
40549
40550            if (!groupElement) {
40551
40552              groupElement = optGroupTemplate.cloneNode(false);
40553              listFragment.appendChild(groupElement);
40554
40555              // Update the label on the group element
40556              // "null" is special cased because of Safari
40557              groupElement.label = option.group === null ? 'null' : option.group;
40558
40559              // Store it for use later
40560              groupElementMap[option.group] = groupElement;
40561            }
40562
40563            addOptionElement(option, groupElement);
40564
40565          } else {
40566
40567            // This option is not in a group
40568            addOptionElement(option, listFragment);
40569          }
40570        });
40571
40572        selectElement[0].appendChild(listFragment);
40573
40574        ngModelCtrl.$render();
40575
40576        // Check to see if the value has changed due to the update to the options
40577        if (!ngModelCtrl.$isEmpty(previousValue)) {
40578          var nextValue = selectCtrl.readValue();
40579          var isNotPrimitive = ngOptions.trackBy || multiple;
40580          if (isNotPrimitive ? !equals(previousValue, nextValue) : previousValue !== nextValue) {
40581            ngModelCtrl.$setViewValue(nextValue);
40582            ngModelCtrl.$render();
40583          }
40584        }
40585
40586      }
40587  }
40588
40589  return {
40590    restrict: 'A',
40591    terminal: true,
40592    require: ['select', 'ngModel'],
40593    link: {
40594      pre: function ngOptionsPreLink(scope, selectElement, attr, ctrls) {
40595        // Deactivate the SelectController.register method to prevent
40596        // option directives from accidentally registering themselves
40597        // (and unwanted $destroy handlers etc.)
40598        ctrls[0].registerOption = noop;
40599      },
40600      post: ngOptionsPostLink
40601    }
40602  };
40603}];
40604
40605/**
40606 * @ngdoc directive
40607 * @name ngPluralize
40608 * @restrict EA
40609 *
40610 * @description
40611 * `ngPluralize` is a directive that displays messages according to en-US localization rules.
40612 * These rules are bundled with angular.js, but can be overridden
40613 * (see {@link guide/i18n Angular i18n} dev guide). You configure ngPluralize directive
40614 * by specifying the mappings between
40615 * [plural categories](http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html)
40616 * and the strings to be displayed.
40617 *
40618 * # Plural categories and explicit number rules
40619 * There are two
40620 * [plural categories](http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html)
40621 * in Angular's default en-US locale: "one" and "other".
40622 *
40623 * While a plural category may match many numbers (for example, in en-US locale, "other" can match
40624 * any number that is not 1), an explicit number rule can only match one number. For example, the
40625 * explicit number rule for "3" matches the number 3. There are examples of plural categories
40626 * and explicit number rules throughout the rest of this documentation.
40627 *
40628 * # Configuring ngPluralize
40629 * You configure ngPluralize by providing 2 attributes: `count` and `when`.
40630 * You can also provide an optional attribute, `offset`.
40631 *
40632 * The value of the `count` attribute can be either a string or an {@link guide/expression
40633 * Angular expression}; these are evaluated on the current scope for its bound value.
40634 *
40635 * The `when` attribute specifies the mappings between plural categories and the actual
40636 * string to be displayed. The value of the attribute should be a JSON object.
40637 *
40638 * The following example shows how to configure ngPluralize:
40639 *
40640 * ```html
40641 * <ng-pluralize count="personCount"
40642                 when="{'0': 'Nobody is viewing.',
40643 *                      'one': '1 person is viewing.',
40644 *                      'other': '{} people are viewing.'}">
40645 * </ng-pluralize>
40646 *```
40647 *
40648 * In the example, `"0: Nobody is viewing."` is an explicit number rule. If you did not
40649 * specify this rule, 0 would be matched to the "other" category and "0 people are viewing"
40650 * would be shown instead of "Nobody is viewing". You can specify an explicit number rule for
40651 * other numbers, for example 12, so that instead of showing "12 people are viewing", you can
40652 * show "a dozen people are viewing".
40653 *
40654 * You can use a set of closed braces (`{}`) as a placeholder for the number that you want substituted
40655 * into pluralized strings. In the previous example, Angular will replace `{}` with
40656 * <span ng-non-bindable>`{{personCount}}
40656`</span>. The closed braces `{}` is a placeholder
40657 * for <span ng-non-bindable>{{numberExpression}}</span>.
40658 *
40659 * If no rule is defined for a category, then an empty string is displayed and a warning is generated.
40660 * Note that some locales define more categories than `one` and `other`. For example, fr-fr defines `few` and `many`.
40661 *
40662 * # Configuring ngPluralize with offset
40663 * The `offset` attribute allows further customization of pluralized text, which can result in
40664 * a better user experience. For example, instead of the message "4 people are viewing this document",
40665 * you might display "John, Kate and 2 others are viewing this document".
40666 * The offset attribute allows you to offset a number by any desired value.
40667 * Let's take a look at an example:
40668 *
40669 * ```html
40670 * <ng-pluralize count="personCount" offset=2
40671 *               when="{'0': 'Nobody is viewing.',
40672 *                      '1': '{{person1}} is viewing.',
40673 *                      '2': '{{person1}} and {{person2}} are viewing.',
40674 *                      'one': '{{person1}}, {{person2}} and one other person are viewing.',
40675 *                      'other': '{{person1}}, {{person2}} and {} other people are viewing.'}">
40676 * </ng-pluralize>
40677 * ```
40678 *
40679 * Notice that we are still using two plural categories(one, other), but we added
40680 * three explicit number rules 0, 1 and 2.
40681 * When one person, perhaps John, views the document, "John is viewing" will be shown.
40682 * When three people view the document, no explicit number rule is found, so
40683 * an offset of 2 is taken off 3, and Angular
vendor: 6,786 bytes, lines 40683-40844
40683 uses 1 to decide the plural category.
40684 * In this case, plural category 'one' is matched and "John, Mary and one other person are viewing"
40685 * is shown.
40686 *
40687 * Note that when you specify offsets, you must provide explicit number rules for
40688 * numbers from 0 up to and including the offset. If you use an offset of 3, for example,
40689 * you must provide explicit number rules for 0, 1, 2 and 3. You must also provide plural strings for
40690 * plural categories "one" and "other".
40691 *
40692 * @param {string|expression} count The variable to be bound to.
40693 * @param {string} when The mapping between plural category to its corresponding strings.
40694 * @param {number=} offset Offset to deduct from the total number.
40695 *
40696 * @example
40697    <example module="pluralizeExample" name="ng-pluralize">
40698      <file name="index.html">
40699        <script>
40700          angular.module('pluralizeExample', [])
40701            .controller('ExampleController', ['$scope', function($scope) {
40702              $scope.person1 = 'Igor';
40703              $scope.person2 = 'Misko';
40704              $scope.personCount = 1;
40705            }]);
40706        </script>
40707        <div ng-controller="ExampleController">
40708          <label>Person 1:<input type="text" ng-model="person1" value="Igor" /></label><br/>
40709          <label>Person 2:<input type="text" ng-model="person2" value="Misko" /></label><br/>
40710          <label>Number of People:<input type="text" ng-model="personCount" value="1" /></label><br/>
40711
40712          <!--- Example with simple pluralization rules for en locale --->
40713          Without Offset:
40714          <ng-pluralize count="personCount"
40715                        when="{'0': 'Nobody is viewing.',
40716                               'one': '1 person is viewing.',
40717                               'other': '{} people are viewing.'}">
40718          </ng-pluralize><br>
40719
40720          <!--- Example with offset --->
40721          With Offset(2):
40722          <ng-pluralize count="personCount" offset=2
40723                        when="{'0': 'Nobody is viewing.',
40724                               '1': '{{person1}} is viewing.',
40725                               '2': '{{person1}} and {{person2}} are viewing.',
40726                               'one': '{{person1}}, {{person2}} and one other person are viewing.',
40727                               'other': '{{person1}}, {{person2}} and {} other people are viewing.'}">
40728          </ng-pluralize>
40729        </div>
40730      </file>
40731      <file name="protractor.js" type="protractor">
40732        it('should show correct pluralized string', function() {
40733          var withoutOffset = element.all(by.css('ng-pluralize')).get(0);
40734          var withOffset = element.all(by.css('ng-pluralize')).get(1);
40735          var countInput = element(by.model('personCount'));
40736
40737          expect(withoutOffset.getText()).toEqual('1 person is viewing.');
40738          expect(withOffset.getText()).toEqual('Igor is viewing.');
40739
40740          countInput.clear();
40741          countInput.sendKeys('0');
40742
40743          expect(withoutOffset.getText()).toEqual('Nobody is viewing.');
40744          expect(withOffset.getText()).toEqual('Nobody is viewing.');
40745
40746          countInput.clear();
40747          countInput.sendKeys('2');
40748
40749          expect(withoutOffset.getText()).toEqual('2 people are viewing.');
40750          expect(withOffset.getText()).toEqual('Igor and Misko are viewing.');
40751
40752          countInput.clear();
40753          countInput.sendKeys('3');
40754
40755          expect(withoutOffset.getText()).toEqual('3 people are viewing.');
40756          expect(withOffset.getText()).toEqual('Igor, Misko and one other person are viewing.');
40757
40758          countInput.clear();
40759          countInput.sendKeys('4');
40760
40761          expect(withoutOffset.getText()).toEqual('4 people are viewing.');
40762          expect(withOffset.getText()).toEqual('Igor, Misko and 2 other people are viewing.');
40763        });
40764        it('should show data-bound names', function() {
40765          var withOffset = element.all(by.css('ng-pluralize')).get(1);
40766          var personCount = element(by.model('personCount'));
40767          var person1 = element(by.model('person1'));
40768          var person2 = element(by.model('person2'));
40769          personCount.clear();
40770          personCount.sendKeys('4');
40771          person1.clear();
40772          person1.sendKeys('Di');
40773          person2.clear();
40774          person2.sendKeys('Vojta');
40775          expect(withOffset.getText()).toEqual('Di, Vojta and 2 other people are viewing.');
40776        });
40777      </file>
40778    </example>
40779 */
40780var ngPluralizeDirective = ['$locale', '$interpolate', '$log', function($locale, $interpolate, $log) {
40781  var BRACE = /{}/g,
40782      IS_WHEN = /^when(Minus)?(.+)$/;
40783
40784  return {
40785    link: function(scope, element, attr) {
40786      var numberExp = attr.count,
40787          whenExp = attr.$attr.when && element.attr(attr.$attr.when), // we have {{}} in attrs
40788          offset = attr.offset || 0,
40789          whens = scope.$eval(whenExp) || {},
40790          whensExpFns = {},
40791          startSymbol = $interpolate.startSymbol(),
40792          endSymbol = $interpolate.endSymbol(),
40793          braceReplacement = startSymbol + numberExp + '-' + offset + endSymbol,
40794          watchRemover = angular.noop,
40795          lastCount;
40796
40797      forEach(attr, function(expression, attributeName) {
40798        var tmpMatch = IS_WHEN.exec(attributeName);
40799        if (tmpMatch) {
40800          var whenKey = (tmpMatch[1] ? '-' : '') + lowercase(tmpMatch[2]);
40801          whens[whenKey] = element.attr(attr.$attr[attributeName]);
40802        }
40803      });
40804      forEach(whens, function(expression, key) {
40805        whensExpFns[key] = $interpolate(expression.replace(BRACE, braceReplacement));
40806
40807      });
40808
40809      scope.$watch(numberExp, function ngPluralizeWatchAction(newVal) {
40810        var count = parseFloat(newVal);
40811        var countIsNaN = isNumberNaN(count);
40812
40813        if (!countIsNaN && !(count in whens)) {
40814          // If an explicit number rule such as 1, 2, 3... is defined, just use it.
40815          // Otherwise, check it against pluralization rules in $locale service.
40816          count = $locale.pluralCat(count - offset);
40817        }
40818
40819        // If both `count` and `lastCount` are NaN, we don't need to re-register a watch.
40820        // In JS `NaN !== NaN`, so we have to explicitly check.
40821        if ((count !== lastCount) && !(countIsNaN && isNumberNaN(lastCount))) {
40822          watchRemover();
40823          var whenExpFn = whensExpFns[count];
40824          if (isUndefined(whenExpFn)) {
40825            if (newVal != null) {
40826              $log.debug('ngPluralize: no rule defined for \'' + count + '\' in ' + whenExp);
40827            }
40828            watchRemover = noop;
40829            updateElementText();
40830          } else {
40831            watchRemover = scope.$watch(whenExpFn, updateElementText);
40832          }
40833          lastCount = count;
40834        }
40835      });
40836
40837      function updateElementText(newText) {
40838        element.text(newText || '');
40839      }
40840    }
40841  };
40842}];
40843
40844/*
40844 exported ngRepeatDirective */
40845
40846/**
40847 * @ngdoc directive
40848 * @name ngRepeat
40849 * @multiElement
40850 * @restrict A
40851 *
40852 * @description
40853 * The `ngRepeat` directive instantiates a template once per item from a collection. Each template
40854 * instance gets its own scope, where the given loop variable is set to the current collection item,
40855 * and `$index` is set to the item index or key.
40856 *
40857 * Special properties are exposed on the local scope of each template instance, including:
40858 *
40859 * | Variable  | Type            | Details                                                                     |
40860 * |-----------|-----------------|-----------------------------------------------------------------------------|
40861 * | `$index`  | {@type number}  | iterator offset of the repeated element (0..length-1)                       |
40862 * | `$first`  | {@type boolean} | true if the repeated element is first in the iterator.                      |
40863 * | `$middle` | {@type boolean} | true if the repeated element is between the first and last in the iterator. |
40864 * | `$last`   | {@type boolean} | true if the repeated element is last in the iterator.                       |
40865 * | `$even`   | {@type boolean} | true if the iterator position `$index` is even (otherwise false).           |
40866 * | `$odd`    | {@type boolean} | true if the iterator position `$index` is odd (otherwise false).            |
40867 *
40868 * <div class="alert alert-info">
40869 *   Creating aliases for these properties is possible with {@link ng.directive:ngInit `ngInit`}.
40870 *   This may be useful when, for instance, nesting ngRepeats.
40871 * </div>
40872 *
40873 *
40874 * # Iterating over object properties
40875 *
40876 * It is possible to get `ngRepeat` to iterate over the properties of an object using the following
40877 * syntax:
40878 *
40879 * ```js
40880 * <div ng-repeat="(key, value) in myObj"> ... </div>
40881 * ```
40882 *
40883 * However, there are a few limitations compared to array iteration:
40884 *
40885 * - The JavaScript specification does not define the order of keys
40886 *   returned for an object, so Angular relies on the order returned by the browser
40887 *   when running `for key in myObj`. Browsers generally follow the strategy of providing
40888 *   keys in the order in which they were defined, although there are exceptions when keys are deleted
40889 *   and reinstated. See the
40890 *   [MDN page on `delete` for more info](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/delete#Cross-browser_notes).
40891 *
40892 * - `ngRepeat` will silently *ignore* object keys starting with `$`, because
40893 *   it's a prefix used by Angular for public (`$`) and private (`$$`) properties.
40894 *
40895 * - The built-in filters {@link ng.orderBy orderBy} and {@link ng.filter filter} do not work with
40896 *   objects, and will throw an error if used with one.
40897 *
40898 * If you are hitting any of these limitations, the recommended workaround is to convert your object into an array
40899 * that is sorted into the order that you prefer before providing it to `ngRepeat`. You could
40900 * do this with a filter such as [toArrayFilter](http://ngmodules.org/modules/angular-toArrayFilter)
40901 * or implement a `$watch` on the object yourself.
40902 *
40903 *
40904 * # Tracking and Duplicates
40905 *
40906 * `ngRepeat` uses {@link $rootScope.Scope#$watchCollection $watchCollection} to detect changes in
40907 * the collection. When a change happens, `ngRepeat` then makes the corresponding changes to the DOM:
40908 *
40909 * * When an item is added, a new instance of the template is added to the DOM.
40910 * * When an item is removed, its template instance is removed from the DOM.
40911 * * When items are reordered, their respective templates are reordered in the DOM.
40912 *
40913 * To minimize creation of DOM elements, `ngRepeat` uses a function
40914 * to "keep track" of all items in the collection and their corresponding DOM elements.
40915 * For example, if an item is added to the collection, `ngRepeat` will know that all other items
40916 * already have DOM elements, and will not re-render them.
40917 *
40918 * The default tracking function (which tracks items by their identity) does not allow
40919 * duplicate items in arrays. This is because when there are duplicates, it is not possible
40920 * to maintain a one-to-one mapping between collection items and DOM elements.
40921 *
40922 * If you do need to repeat duplicate items, you can substitute the default tracking behavior
40923 * with your own using the `track by` expression.
40924 *
40925 * For example, you may track items by the index of each item in the collection, using the
40926 * special scope property `$index`:
40927 * ```html
40928 *    <div ng-repeat="n in [42, 42, 43, 43] track by $index">
40929 *      {{n}}
40930 *    </div>
40931 * ```
40932 *
40933 * You may also use arbitrary expressions in `track by`, including references to custom functions
40934 * on the scope:
40935 * ```html
40936 *    <div ng-repeat="n in [42, 42, 43, 43] track by myTrackingFunction(n)">
40937 *      {{n}}
40938 *    </div>
40939 * ```
40940 *
40941 * <div class="alert alert-success">
40942 * If you are working with objects that have a unique identifier property, you should track
40943 * by this identifier instead of the object instance. Should you reload your data later, `ngRepeat`
40944 * will not have to rebuild the DOM elements for items it has already rendered, even if the
40945 * JavaScript objects in the collection have been substituted for new ones. For large collections,
40946 * this significantly improves rendering performance. If you don't have a unique identifier,
40947 * `track by $index` can also provide a performance boost.
40948 * </div>
40949 *
40950 * ```html
40951 *    <div ng-repeat="model in collection track by model.id">
40952 *      {{model.name}}
40953 *    </div>
40954 * ```
40955 *
40956 * <br />
40957 * <div class="alert alert-warning">
40958 * Avoid using `track by $index` when the repeated template contains
40959 * {@link guide/expression#one-time-binding one-time bindings}. In such cases, the `nth` DOM
40960 * element will always be matched with the `nth` item of the array, so the bindings on that element
40961 * will not be updated even when the corresponding item changes, essentially causing the view to get
40962 * out-of-sync with the underlying data.
40963 * </div>
40964 *
40965 * When no `track by` expression is provided, it is equivalent to tracking by the built-in
40966 * `$id` function, which tracks items by their identity:
40967 * ```html
40968 *    <div ng-repeat="obj in collection track by $id(obj)">
40969 *      {{obj.prop}}
40970 *    </div>
40971 * ```
40972 *
40973 * <br />
40974 * <div class="alert alert-warning">
40975 * **Note:** `track by` must always be the last expression:
40976 * </div>
40977 * ```
40978 *    <div ng-repeat="model in collection | orderBy: 'id' as filtered_result track by model.id">
40979 *      {{model.name}}
40980 *    </div>
40981 * ```
40982 *
40983 *
40984 * # Special repeat start and end points
40985 * To repeat a series of elements instead of just one parent element, ngRepeat (as well as other ng directives) supports extending
40986 * the range of the repeater by defining explicit start and end points by using **ng-repeat-start** and **ng-repeat-end** respectively.
40987 * 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)
40988 * up to and including the ending HTML tag where **ng-repeat-end** is placed.
40989 *
40990 * The example below makes use of this feature:
40991 * ```html
40992 *   <header ng-repeat-start="item in items">
40993 *     Header {{ item }}
40994 *   </header>
40995 *   <div class="body">
40996 *     Body {{ item }}
40997 *   </div>
40998 *   <footer ng-repeat-end>
40999 *     Footer {{ item }}
41000 *   </footer>
41001 * ```
41002 *
41003 * And with an input of {@type ['A','B']} for the items variable in the example above, the output will evaluate to:
41004 * ```html
41005 *   <header>
41006 *     Header A
41007 *   </header>
41008 *   <div class="body">
41009 *     Body A
41010 *   </div>
41011 *   <footer>
41012 *     Footer A
41013 *   </footer>
41014 *   <header>
41015 *     Header B
41016 *   </header>
41017 *   <div class="body">
41018 *     Body B
41019 *   </div>
41020 *   <footer>
41021 *     Footer B
41022 *   </footer>
41023 * ```
41024 *
41025 * The custom start and end points for ngRepeat also support all other HTML directive syntax flavors provided in AngularJS (such
41026 * as **data-ng-repeat-start**, **x-ng-repeat-start** and **ng:repeat-start**).
41027 *
41028 * @animations
41029 * | Animation                        | Occurs                              |
41030 * |----------------------------------|-------------------------------------|
41031 * | {@link ng.$animate#enter enter} | when a new item is added to the list or when an item is revealed after a filter |
41032 * | {@link ng.$animate#leave leave} | when an item is removed from the list or when an item is filtered out |
41033 * | {@link ng.$animate#move move } | when an adjacent item is filtered out causing a reorder or when the item contents are reordered |
41034 *
41035 * See the example below for defining CSS animations with ngRepeat.
41036 *
41037 * @element ANY
41038 * @scope
41039 * @priority 1000
41040 * @param {repeat_expression} ngRepeat The expression indicating how to enumerate a collection. These
41041 *   formats are currently supported:
41042 *
41043 *   * `variable in expression` – where variable is the user defined loop variable and `expression`
41044 *     is a scope expression giving the collection to enumerate.
41045 *
41046 *     For example: `album in artist.albums`.
41047 *
41048 *   * `(key, value) in expression` – where `key` and `value` can be any user defined identifiers,
41049 *     and `expression` is the scope expression giving the collection to enumerate.
41050 *
41051 *     For example: `(name, age) in {'adam':10, 'amalie':12}`.
41052 *
41053 *   * `variable in expression track by tracking_expression` – You can also provide an optional tracking expression
41054 *     which can be used to associate the objects in the collection with the DOM elements. If no tracking expression
41055 *     is specified, ng-repeat associates elements by identity. It is an error to have
41056 *     more than one tracking expression value resolve to the same key. (This would mean that two distinct objects are
41057 *     mapped to the same DOM element, which is not possible.)
41058 *
41059 *     Note that the tracking expression must come last, after any filters, and the alias expression.
41060 *
41061 *     For example: `item in items` is equivalent to `item in items track by $id(item)`. This implies that the DOM elements
41062 *     will be associated by item identity in the array.
41063 *
41064 *     For example: `item in items track by $id(item)`. A built in `$id()` function can be used to assign a unique
41065 *     `$$hashKey` property to each item in the array. This property is then used as a key to associated DOM elements
41066 *     with the corresponding item in the array by identity. Moving the same object in array would move the DOM
41067 *     element in the same way in the DOM.
41068 *
41069 *     For example: `item in items track by item.id` is a typical pattern when the items come from the database. In this
41070 *     case the object identity does not matter. Two objects are considered equivalent as long as their `id`
41071 *     property is same.
41072 *
41073 *     For example: `item in items | filter:searchText track by item.id` is a pattern that might be used to apply a filter
41074 *     to items in conjunction with a tracking expression.
41075 *
41076 *   * `variable in expression as alias_expression` – You can also provide an optional alias expression which will then store the
41077 *     intermediate results of the repeater after the filters have been applied. Typically this is used to render a special message
41078 *     when a filter is active on the repeater, but the filtered result set is empty.
41079 *
41080 *     For example: `item in items | filter:x as results` will store the fragment of the repeated items as `results`, but only after
41081 *     the items have been processed through the filter.
41082 *
41083 *     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
41084 *     (and not as operator, inside an expression).
41085 *
41086 *     For example: `item in items | filter : x | orderBy : order | limitTo : limit as results` .
41087 *
41088 * @example
41089 * This example uses `ngRepeat` to display a list of people. A filter is used to restrict the displayed
41090 * results by name or by age. New (entering) and removed (leaving) items are animated.
41091  <example module="ngRepeat" name="ngRepeat" deps="angular-animate.js" animations="true" name="ng-repeat">
41092    <file name="index.html">
41093      <div ng-controller="repeatController">
41094        I have {{friends.length}} friends. They are:
41095        <input type="search" ng-model="q" placeholder="filter friends..." aria-label="filter friends" />
41096        <ul class="example-animate-container">
41097          <li class="animate-repeat" ng-repeat="friend in friends | filter:q as results">
41098            [{{$index + 1}}] {{friend.name}} who is {{friend.age}} years old.
41099          </li>
41100          <li class="animate-repeat" ng-if="results.length === 0">
41101            <strong>No results found...</strong>
41102          </li>
41103        </ul>
41104      </div>
41105    </file>
41106    <file name="script.js">
41107      angular.module('ngRepeat', ['ngAnimate']).controller('repeatController', function($scope) {
41108        $scope.friends = [
41109          {name:'John', age:25, gender:'boy'},
41110          {name:'Jessie', age:30, gender:'girl'},
41111          {name:'Johanna', age:28, gender:'girl'},
41112          {name:'Joy', age:15, gender:'girl'},
41113          {name:'Mary', age:28, gender:'girl'},
41114          {name:'Peter', age:95, gender:'boy'},
41115          {name:'Sebastian', age:50, gender:'boy'},
41116          {name:'Erika', age:27, gender:'girl'},
41117          {name:'Patrick', age:40, gender:'boy'},
41118          {name:'Samantha', age:60, gender:'girl'}
41119        ];
41120      });
41121    </file>
41122    <file name="animations.css">
41123      .example-animate-container {
41124        background:white;
41125        border:1px solid black;
41126        list-style:none;
41127        margin:0;
41128        padding:0 10px;
41129      }
41130
41131      .animate-repeat {
41132        line-height:30px;
41133        list-style:none;
41134        box-sizing:border-box;
41135      }
41136
41137      .animate-repeat.ng-move,
41138      .animate-repeat.ng-enter,
41139      .animate-repeat.ng-leave {
41140        transition:all linear 0.5s;
41141      }
41142
41143      .animate-repeat.ng-leave.ng-leave-active,
41144      .animate-repeat.ng-move,
41145      .animate-repeat.ng-enter {
41146        opacity:0;
41147        max-height:0;
41148      }
41149
41150      .animate-repeat.ng-leave,
41151      .animate-repeat.ng-move.ng-move-active,
41152      .animate-repeat.ng-enter.ng-enter-active {
41153        opacity:1;
41154        max-height:30px;
41155      }
41156    </file>
41157    <file name="protractor.js" type="protractor">
41158      var friends = element.all(by.repeater('friend in friends'));
41159
41160      it('should render initial data set', function() {
41161        expect(friends.count()).toBe(10);
41162        expect(friends.get(0).getText()).toEqual('[1] John who is 25 years old.');
41163        expect(friends.get(1).getText()).toEqual('[2] Jessie who is 30 years old.');
41164        expect(friends.last().getText()).toEqual('[10] Samantha who is 60 years old.');
41165        expect(element(by.binding('friends.length')).getText())
41166            .toMatch("I have 10 friends. They are:");
41167      });
41168
41169       it('should update repeater when filter predicate changes', function() {
41170         expect(friends.count()).toBe(10);
41171
41172         element(by.model('q')).sendKeys('ma');
41173
41174         expect(friends.count()).toBe(2);
41175         expect(friends.get(0).getText()).toEqual('[1] Mary who is 28 years old.');
41176         expect(friends.last().getText()).toEqual('[2] Samantha who is 60 years old.');
41177       });
41178      </file>
41179    </example>
41180 */
41181var ngRepeatDirective = ['$parse', '$animate', '$compile', function($parse, $animate, $compile) {
41182  var NG_REMOVED = '$$NG_REMOVED';
41183  var ngRepeatMinErr = minErr('ngRepeat');
41184
41185  var updateScope = function(scope, index, valueIdentifier, value, keyIdentifier, key, arrayLength) {
41186    // TODO(perf): generate setters to shave off ~40ms or 1-1.5%
41187    scope[valueIdentifier] = value;
41188    if (keyIdentifier) scope[keyIdentifier] = key;
41189    scope.$index = index;
41190    scope.$first = (index === 0);
41191    scope.$last = (index === (arrayLength - 1));
41192    scope.$middle = !(scope.$first || scope.$last);
41193    // eslint-disable-next-line no-bitwise
41194    scope.$odd = !(scope.$even = (index & 1) === 0);
41195  };
41196
41197  var getBlockStart = function(block) {
41198    return block.clone[0];
41199  };
41200
41201  var getBlockEnd = function(block) {
41202    return block.clone[block.clone.length - 1];
41203  };
41204
41205
41206  return {
41207    restrict: 'A',
41208    multiElement: true,
41209    transclude: 'element',
41210    priority: 1000,
41211    terminal: true,
41212    $$tlb: true,
41213    compile: function ngRepeatCompile($element, $attr) {
41214      var expression = $attr.ngRepeat;
41215      var ngRepeatEndComment = $compile.$$createComment('end ngRepeat', expression);
41216
41217      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*$/);
41218
41219      if (!match) {
41220        throw ngRepeatMinErr('iexp', 'Expected expression in form of \'_item_ in _collection_[ track by _id_]\' but got \'{0}\'.',
41221            expression);
41222      }
41223
41224      var lhs = match[1];
41225      var rhs = match[2];
41226      var aliasAs = match[3];
41227      var trackByExp = match[4];
41228
41229      match = lhs.match(/^(?:(\s*[$\w]+)|\(\s*([$\w]+)\s*,\s*([$\w]+)\s*\))$/);
41230
41231      if (!match) {
41232        throw ngRepeatMinErr('iidexp', '\'_item_\' in \'_item_ in _collection_\' should be an identifier or \'(_key_, _value_)\' expression, but got \'{0}\'.',
41233            lhs);
41234      }
41235      var valueIdentifier = match[3] || match[1];
41236      var keyIdentifier = match[2];
41237
41238      if (aliasAs && (!/^[$a-zA-Z_][$a-zA-Z0-9_]*$/.test(aliasAs) ||
41239          /^(null|undefined|this|\$index|\$first|\$middle|\$last|\$even|\$odd|\$parent|\$root|\$id)$/.test(aliasAs))) {
41240        throw ngRepeatMinErr('badident', 'alias \'{0}\' is invalid --- must be a valid JS identifier which is not a reserved name.',
41241          aliasAs);
41242      }
41243
41244      var trackByExpGetter, trackByIdExpFn, trackByIdArrayFn, trackByIdObjFn;
41245      var hashFnLocals = {$id: hashKey};
41246
41247      if (trackByExp) {
41248        trackByExpGetter = $parse(trackByExp);
41249      } else {
41250        trackByIdArrayFn = function(key, value) {
41251          return hashKey(value);
41252        };
41253        trackByIdObjFn = function(key) {
41254          return key;
41255        };
41256      }
41257
41258      return function ngRepeatLink($scope, $element, $attr, ctrl, $transclude) {
41259
41260        if (trackByExpGetter) {
41261          trackByIdExpFn = function(key, value, index) {
vendor: 14,350 bytes, lines 41262-41604
41262            // assign key, value, and $index to the locals so that they can be used in hash functions
41263            if (keyIdentifier) hashFnLocals[keyIdentifier] = key;
41264            hashFnLocals[valueIdentifier] = value;
41265            hashFnLocals.$index = index;
41266            return trackByExpGetter($scope, hashFnLocals);
41267          };
41268        }
41269
41270        // Store a list of elements from previous run. This is a hash where key is the item from the
41271        // iterator, and the value is objects with following properties.
41272        //   - scope: bound scope
41273        //   - element: previous element.
41274        //   - index: position
41275        //
41276        // We are using no-proto object so that we don't need to guard against inherited props via
41277        // hasOwnProperty.
41278        var lastBlockMap = createMap();
41279
41280        //watch props
41281        $scope.$watchCollection(rhs, function ngRepeatAction(collection) {
41282          var index, length,
41283              previousNode = $element[0],     // node that cloned nodes should be inserted after
41284                                              // initialized to the comment node anchor
41285              nextNode,
41286              // Same as lastBlockMap but it has the current state. It will become the
41287              // lastBlockMap on the next iteration.
41288              nextBlockMap = createMap(),
41289              collectionLength,
41290              key, value, // key/value of iteration
41291              trackById,
41292              trackByIdFn,
41293              collectionKeys,
41294              block,       // last object information {scope, element, id}
41295              nextBlockOrder,
41296              elementsToRemove;
41297
41298          if (aliasAs) {
41299            $scope[aliasAs] = collection;
41300          }
41301
41302          if (isArrayLike(collection)) {
41303            collectionKeys = collection;
41304            trackByIdFn = trackByIdExpFn || trackByIdArrayFn;
41305          } else {
41306            trackByIdFn = trackByIdExpFn || trackByIdObjFn;
41307            // if object, extract keys, in enumeration order, unsorted
41308            collectionKeys = [];
41309            for (var itemKey in collection) {
41310              if (hasOwnProperty.call(collection, itemKey) && itemKey.charAt(0) !== '$') {
41311                collectionKeys.push(itemKey);
41312              }
41313            }
41314          }
41315
41316          collectionLength = collectionKeys.length;
41317          nextBlockOrder = new Array(collectionLength);
41318
41319          // locate existing items
41320          for (index = 0; index < collectionLength; index++) {
41321            key = (collection === collectionKeys) ? index : collectionKeys[index];
41322            value = collection[key];
41323            trackById = trackByIdFn(key, value, index);
41324            if (lastBlockMap[trackById]) {
41325              // found previously seen block
41326              block = lastBlockMap[trackById];
41327              delete lastBlockMap[trackById];
41328              nextBlockMap[trackById] = block;
41329              nextBlockOrder[index] = block;
41330            } else if (nextBlockMap[trackById]) {
41331              // if collision detected. restore lastBlockMap and throw an error
41332              forEach(nextBlockOrder, function(block) {
41333                if (block && block.scope) lastBlockMap[block.id] = block;
41334              });
41335              throw ngRepeatMinErr('dupes',
41336                  'Duplicates in a repeater are not allowed. Use \'track by\' expression to specify unique keys. Repeater: {0}, Duplicate key: {1}, Duplicate value: {2}',
41337                  expression, trackById, value);
41338            } else {
41339              // new never before seen block
41340              nextBlockOrder[index] = {id: trackById, scope: undefined, clone: undefined};
41341              nextBlockMap[trackById] = true;
41342            }
41343          }
41344
41345          // remove leftover items
41346          for (var blockKey in lastBlockMap) {
41347            block = lastBlockMap[blockKey];
41348            elementsToRemove = getBlockNodes(block.clone);
41349            $animate.leave(elementsToRemove);
41350            if (elementsToRemove[0].parentNode) {
41351              // if the element was not removed yet because of pending animation, mark it as deleted
41352              // so that we can ignore it later
41353              for (index = 0, length = elementsToRemove.length; index < length; index++) {
41354                elementsToRemove[index][NG_REMOVED] = true;
41355              }
41356            }
41357            block.scope.$destroy();
41358          }
41359
41360          // we are not using forEach for perf reasons (trying to avoid #call)
41361          for (index = 0; index < collectionLength; index++) {
41362            key = (collection === collectionKeys) ? index : collectionKeys[index];
41363            value = collection[key];
41364            block = nextBlockOrder[index];
41365
41366            if (block.scope) {
41367              // if we have already seen this object, then we need to reuse the
41368              // associated scope/element
41369
41370              nextNode = previousNode;
41371
41372              // skip nodes that are already pending removal via leave animation
41373              do {
41374                nextNode = nextNode.nextSibling;
41375              } while (nextNode && nextNode[NG_REMOVED]);
41376
41377              if (getBlockStart(block) !== nextNode) {
41378                // existing item which got moved
41379                $animate.move(getBlockNodes(block.clone), null, previousNode);
41380              }
41381              previousNode = getBlockEnd(block);
41382              updateScope(block.scope, index, valueIdentifier, value, keyIdentifier, key, collectionLength);
41383            } else {
41384              // new item which we don't know about
41385              $transclude(function ngRepeatTransclude(clone, scope) {
41386                block.scope = scope;
41387                // http://jsperf.com/clone-vs-createcomment
41388                var endNode = ngRepeatEndComment.cloneNode(false);
41389                clone[clone.length++] = endNode;
41390
41391                $animate.enter(clone, null, previousNode);
41392                previousNode = endNode;
41393                // Note: We only need the first/last node of the cloned nodes.
41394                // However, we need to keep the reference to the jqlite wrapper as it might be changed later
41395                // by a directive with templateUrl when its template arrives.
41396                block.clone = clone;
41397                nextBlockMap[block.id] = block;
41398                updateScope(block.scope, index, valueIdentifier, value, keyIdentifier, key, collectionLength);
41399              });
41400            }
41401          }
41402          lastBlockMap = nextBlockMap;
41403        });
41404      };
41405    }
41406  };
41407}];
41408
41409var NG_HIDE_CLASS = 'ng-hide';
41410var NG_HIDE_IN_PROGRESS_CLASS = 'ng-hide-animate';
41411/**
41412 * @ngdoc directive
41413 * @name ngShow
41414 * @multiElement
41415 *
41416 * @description
41417 * The `ngShow` directive shows or hides the given HTML element based on the expression provided to
41418 * the `ngShow` attribute.
41419 *
41420 * The element is shown or hidden by removing or adding the `.ng-hide` CSS class onto the element.
41421 * The `.ng-hide` CSS class is predefined in AngularJS and sets the display style to none (using an
41422 * `!important` flag). For CSP mode please add `angular-csp.css` to your HTML file (see
41423 * {@link ng.directive:ngCsp ngCsp}).
41424 *
41425 * ```html
41426 * <!-- when $scope.myValue is truthy (element is visible) -->
41427 * <div ng-show="myValue"></div>
41428 *
41429 * <!-- when $scope.myValue is falsy (element is hidden) -->
41430 * <div ng-show="myValue" class="ng-hide"></div>
41431 * ```
41432 *
41433 * When the `ngShow` expression evaluates to a falsy value then the `.ng-hide` CSS class is added
41434 * to the class attribute on the element causing it to become hidden. When truthy, the `.ng-hide`
41435 * CSS class is removed from the element causing the element not to appear hidden.
41436 *
41437 * ## Why is `!important` used?
41438 *
41439 * You may be wondering why `!important` is used for the `.ng-hide` CSS class. This is because the
41440 * `.ng-hide` selector can be easily overridden by heavier selectors. For example, something as
41441 * simple as changing the display style on a HTML list item would make hidden elements appear
41442 * visible. This also becomes a bigger issue when dealing with CSS frameworks.
41443 *
41444 * By using `!important`, the show and hide behavior will work as expected despite any clash between
41445 * CSS selector specificity (when `!important` isn't used with any conflicting styles). If a
41446 * developer chooses to override the styling to change how to hide an element then it is just a
41447 * matter of using `!important` in their own CSS code.
41448 *
41449 * ### Overriding `.ng-hide`
41450 *
41451 * By default, the `.ng-hide` class will style the element with `display: none !important`. If you
41452 * wish to change the hide behavior with `ngShow`/`ngHide`, you can simply overwrite the styles for
41453 * the `.ng-hide` CSS class. Note that the selector that needs to be used is actually
41454 * `.ng-hide:not(.ng-hide-animate)` to cope with extra animation classes that can be added.
41455 *
41456 * ```css
41457 * .ng-hide:not(.ng-hide-animate) {
41458 *   /&#42; These are just alternative ways of hiding an element &#42;/
41459 *   display: block!important;
41460 *   position: absolute;
41461 *   top: -9999px;
41462 *   left: -9999px;
41463 * }
41464 * ```
41465 *
41466 * By default you don't need to override anything in CSS and the animations will work around the
41467 * display style.
41468 *
41469 * ## A note about animations with `ngShow`
41470 *
41471 * Animations in `ngShow`/`ngHide` work with the show and hide events that are triggered when the
41472 * directive expression is true and false. This system works like the animation system present with
41473 * `ngClass` except that you must also include the `!important` flag to override the display
41474 * property so that the elements are not actually hidden during the animation.
41475 *
41476 * ```css
41477 * /&#42; A working example can be found at the bottom of this page. &#42;/
41478 * .my-element.ng-hide-add, .my-element.ng-hide-remove {
41479 *   transition: all 0.5s linear;
41480 * }
41481 *
41482 * .my-element.ng-hide-add { ... }
41483 * .my-element.ng-hide-add.ng-hide-add-active { ... }
41484 * .my-element.ng-hide-remove { ... }
41485 * .my-element.ng-hide-remove.ng-hide-remove-active { ... }
41486 * ```
41487 *
41488 * Keep in mind that, as of AngularJS version 1.3, there is no need to change the display property
41489 * to block during animation states - ngAnimate will automatically handle the style toggling for you.
41490 *
41491 * @animations
41492 * | Animation                                           | Occurs                                                                                                        |
41493 * |-----------------------------------------------------|---------------------------------------------------------------------------------------------------------------|
41494 * | {@link $animate#addClass addClass} `.ng-hide`       | After the `ngShow` expression evaluates to a non truthy value and just before the contents are set to hidden. |
41495 * | {@link $animate#removeClass removeClass} `.ng-hide` | After the `ngShow` expression evaluates to a truthy value and just before contents are set to visible.        |
41496 *
41497 * @element ANY
41498 * @param {expression} ngShow If the {@link guide/expression expression} is truthy/falsy then the
41499 *                            element is shown/hidden respectively.
41500 *
41501 * @example
41502 * A simple example, animating the element's opacity:
41503 *
41504  <example module="ngAnimate" deps="angular-animate.js" animations="true" name="ng-show-simple">
41505    <file name="index.html">
41506      Show: <input type="checkbox" ng-model="checked" aria-label="Toggle ngShow"><br />
41507      <div class="check-element animate-show-hide" ng-show="checked">
41508        I show up when your checkbox is checked.
41509      </div>
41510    </file>
41511    <file name="animations.css">
41512      .animate-show-hide.ng-hide {
41513        opacity: 0;
41514      }
41515
41516      .animate-show-hide.ng-hide-add,
41517      .animate-show-hide.ng-hide-remove {
41518        transition: all linear 0.5s;
41519      }
41520
41521      .check-element {
41522        border: 1px solid black;
41523        opacity: 1;
41524        padding: 10px;
41525      }
41526    </file>
41527    <file name="protractor.js" type="protractor">
41528      it('should check ngShow', function() {
41529        var checkbox = element(by.model('checked'));
41530        var checkElem = element(by.css('.check-element'));
41531
41532        expect(checkElem.isDisplayed()).toBe(false);
41533        checkbox.click();
41534        expect(checkElem.isDisplayed()).toBe(true);
41535      });
41536    </file>
41537  </example>
41538 *
41539 * <hr />
41540 * @example
41541 * A more complex example, featuring different show/hide animations:
41542 *
41543  <example module="ngAnimate" deps="angular-animate.js" animations="true" name="ng-show-complex">
41544    <file name="index.html">
41545      Show: <input type="checkbox" ng-model="checked" aria-label="Toggle ngShow"><br />
41546      <div class="check-element funky-show-hide" ng-show="checked">
41547        I show up when your checkbox is checked.
41548      </div>
41549    </file>
41550    <file name="animations.css">
41551      body {
41552        overflow: hidden;
41553        perspective: 1000px;
41554      }
41555
41556      .funky-show-hide.ng-hide-add {
41557        transform: rotateZ(0);
41558        transform-origin: right;
41559        transition: all 0.5s ease-in-out;
41560      }
41561
41562      .funky-show-hide.ng-hide-add.ng-hide-add-active {
41563        transform: rotateZ(-135deg);
41564      }
41565
41566      .funky-show-hide.ng-hide-remove {
41567        transform: rotateY(90deg);
41568        transform-origin: left;
41569        transition: all 0.5s ease;
41570      }
41571
41572      .funky-show-hide.ng-hide-remove.ng-hide-remove-active {
41573        transform: rotateY(0);
41574      }
41575
41576      .check-element {
41577        border: 1px solid black;
41578        opacity: 1;
41579        padding: 10px;
41580      }
41581    </file>
41582    <file name="protractor.js" type="protractor">
41583      it('should check ngShow', function() {
41584        var checkbox = element(by.model('checked'));
41585        var checkElem = element(by.css('.check-element'));
41586
41587        expect(checkElem.isDisplayed()).toBe(false);
41588        checkbox.click();
41589        expect(checkElem.isDisplayed()).toBe(true);
41590      });
41591    </file>
41592  </example>
41593 */
41594var ngShowDirective = ['$animate', function($animate) {
41595  return {
41596    restrict: 'A',
41597    multiElement: true,
41598    link: function(scope, element, attr) {
41599      scope.$watch(attr.ngShow, function ngShowWatchAction(value) {
41600        // we're adding a temporary, animation-specific class for ng-hide since this way
41601        // we can control when the element is actually displayed on screen without having
41602        // to have a global/greedy CSS selector that breaks when other animations are run.
41603        // Read: https://github.com/angular/angular.js/issues/9103#issuecomment-58335845
41604        $animate[value ? 'removeClass' : 'addClass'](element, NG_HIDE_CLASS, {
41605          tempClasses: NG_HIDE_IN_PROGRESS_CLASS
41606        });
41607      });
41608    }
41609  };
41610}];
41611
41612
41613/**
41614 * @ngdoc directive
41615 * @name ngHide
41616 * @multiElement
41617 *
41618 * @description
41619 * The `ngHide` directive shows or hides the given HTML element based on the expression provided to
41620 * the `ngHide` attribute.
41621 *
41622 * The element is shown or hidden by removing or adding the `.ng-hide` CSS class onto the element.
41623 * The `.ng-hide` CSS class is predefined in AngularJS and sets the display style to none (using an
41624 * `!important` flag). For CSP mode please add `angular-csp.css` to your HTML file (see
41625 * {@link ng.directive:ngCsp ngCsp}).
41626 *
41627 * ```html
41628 * <!-- when $scope.myValue is truthy (element is hidden) -->
41629 * <div ng-hide="myValue" class="ng-hide"></div>
41630 *
41631 * <!-- when $scope.myValue is falsy (element is visible) -->
41632 * <div ng-hide="myValue"></div>
41633 * ```
41634 *
41635 * When the `ngHide` expression evaluates to a truthy value then the `.ng-hide` CSS class is added
41636 * to the class attribute on the element causing it to become hidden. When falsy, the `.ng-hide`
41637 * CSS class is removed from the element causing the element not to appear hidden.
41638 *
41639 * ## Why is `!important` used?
41640 *
41641 * You may be wondering why `!important` is used for the `.ng-hide` CSS class. This is because the
41642 * `.ng-hide` selector can be easily overridden by heavier selectors. For example, something as
41643 * simple as changing the display style on a HTML list item would make hidden elements appear
41644 * visible. This also becomes a bigger issue when dealing with CSS frameworks.
41645 *
41646 * By using `!important`, the show and hide behavior will work as expected despite any clash between
41647 * CSS selector specificity (when `!important` isn't used with any conflicting styles). If a
41648 * developer chooses to override the styling to change how to hide an element then it is just a
41649 * matter of using `!important` in their own CSS code.
41650 *
41651 * ### Overriding `.ng-hide`
41652 *
41653 * By default, the `.ng-hide` class will style the element with `display: none !important`. If you
41654 * wish to change the hide behavior with `ngShow`/`ngHide`, you can simply overwrite the styles for
41655 * the `.ng-hide` CSS class. Note that the selector that needs to be used is actually
41656 * `.ng-hide:not(.ng-hide-animate)` to cope with extra animation classes that can be added.
41657 *
41658 * ```css
41659 * .ng-hide:not(.ng-hide-animate) {
41660 *   /&#42; These are just alternative ways of hiding an element &#42;/
41661 *   display: block!important;
41662 *   position: absolute;
41663 *   top: -9999px;
41664 *   left: -9999px;
41665 * }
41666 * ```
41667 *
41668 * By default you don't need to override in CSS anything and the animations will work around the
41669 * display style.
41670 *
41671 * ## A note about animations with `ngHide`
41672 *
41673 * Animations in `ngShow`/`ngHide` work with the show and hide events that are triggered when the
41674 * directive expression is true and false. This system works like the animation system present with
41675 * `ngClass` except that you must also include the `!important` flag to override the display
41676 * property so that the elements are not actually hidden during the animation.
41677 *
41678 * ```css
41679 * /&#42; A working example can be found at the bottom of this page. &#42;/
41680 * .my-element.ng-hide-add, .my-element.ng-hide-remove {
41681 *   transition: all 0.5s linear;
41682 * }
41683 *
41684 * .my-element.ng-hide-add { ... }
41685 * .my-element.ng-hide-add.ng-hide-add-active { ... }
41686 * .my-element.ng-hide-remove { ... }
41687 * .my-element.ng-hide-remove.ng-hide-remove-active { ... }
41688 * ```
41689 *
41690 * Keep in mind that, as of AngularJS version 1.3, there is no need to change the display property
41691 * to block during animation states - ngAnimate will automatically handle the style toggling for you.
41692 *
41693 * @animations
41694 * | Animation                                           | Occurs                                                                                                     |
41695 * |-----------------------------------------------------|------------------------------------------------------------------------------------------------------------|
41696 * | {@link $animate#addClass addClass} `.ng-hide`       | After the `ngHide` expression evaluates to a truthy value and just before the contents are set to hidden.  |
41697 * | {@link $animate#removeClass removeClass} `.ng-hide` | After the `ngHide` expression evaluates to a non truthy value and just before contents are set to visible. |
41698 *
41699 *
41700 * @element ANY
41701 * @param {expression} ngHide If the {@link guide/expression expression} is truthy/falsy then the
41702 *                            element is hidden/shown respectively.
41703 *
41704 * @example
41705 * A simple example, animating the element's opacity:
41706 *
41707  <example module="ngAnimate" deps="angular-animate.js" animations="true" name="ng-hide-simple">
41708    <file name="index.html">
41709      Hide: <input type="checkbox" ng-model="checked" aria-label="Toggle ngHide"><br />
41710      <div class="check-element animate-show-hide" ng-hide="checked">
41711        I hide when your checkbox is checked.
41712      </div>
41713    </file>
41714    <file name="animations.css">
41715      .animate-show-hide.ng-hide {
41716        opacity: 0;
41717      }
41718
41719      .animate-show-hide.ng-hide-add,
41720      .animate-show-hide.ng-hide-remove {
41721        transition: all linear 0.5s;
41722      }
41723
41724      .check-element {
41725        border: 1px solid black;
41726        opacity: 1;
41727        padding: 10px;
41728      }
41729    </file>
41730    <file name="protractor.js" type="protractor">
41731      it('should check ngHide', function() {
41732        var checkbox = element(by.model('checked'));
41733        var checkElem = element(by.css('.check-element'));
41734
41735        expect(checkElem.isDisplayed()).toBe(true);
41736        checkbox.click();
41737        expect(checkElem.isDisplayed()).toBe(false);
41738      });
41739    </file>
41740  </example>
41741 *
41742 * <hr />
41743 * @example
41744 * A more complex example, featuring different show/hide animations:
41745 *
41746  <example module="ngAnimate" deps="angular-animate.js" animations="true" name="ng-hide-complex">
41747    <file name="index.html">
41748      Hide: <input type="checkbox" ng-model="checked" aria-label="Toggle ngHide"><br />
41749      <div class="check-element funky-show-hide" ng-hide="checked">
41750        I hide when your checkbox is checked.
41751      </div>
41752    </file>
41753    <file name="animations.css">
41754      body {
41755        overflow: hidden;
41756        perspective: 1000px;
41757      }
41758
41759      .funky-show-hide.ng-hide-add {
41760        transform: rotateZ(0);
41761        transform-origin: right;
41762        transition: all 0.5s ease-in-out;
41763      }
41764
41765      .funky-show-hide.ng-hide-add.ng-hide-add-active {
41766        transform: rotateZ(-135deg);
41767      }
41768
41769      .funky-show-hide.ng-hide-remove {
41770        transform: rotateY(90deg);
41771        transform-origin: left;
41772        transition: all 0.5s ease;
41773      }
41774
41775      .funky-show-hide.ng-hide-remove.ng-hide-remove-active {
41776        transform: rotateY(0);
41777      }
41778
41779      .check-element {
41780        border: 1px solid black;
41781        opacity: 1;
41782        padding: 10px;
41783      }
41784    </file>
41785    <file name="protractor.js" type="protractor">
41786      it('should check ngHide', function() {
41787        var checkbox = element(by.model('checked'));
41788        var checkElem = element(by.css('.check-element'));
41789
41790        expect(checkElem.isDisplayed()).toBe(true);
41791        checkbox.click();
41792        expect(checkElem.isDisplayed()).toBe(false);
41793      });
41794    </file>
41795  </example>
41796 */
41797var ngHideDirective = ['$animate', function($animate) {
41798  return {
41799    restrict: 'A',
41800    multiElement: true,
41801    link: function(scope, element, attr) {
41802      scope.$watch(attr.ngHide, function ngHideWatchAction(value) {
41803        // The comment inside of the ngShowDirective explains why we add and
41804        // remove a temporary class for the show/hide animation
41805        $animate[value ? 'addClass' : 'removeClass'](element,NG_HIDE_CLASS, {
41806          tempClasses: NG_HIDE_IN_PROGRESS_CLASS
41807        });
41808      });
41809    }
41810  };
41811}];
41812
41813/**
41814 * @ngdoc directive
41815 * @name ngStyle
41816 * @restrict AC
41817 *
41818 * @description
41819 * The `ngStyle` directive allows you to set CSS style on an HTML element conditionally.
41820 *
41821 * @knownIssue
41822 * You should not use {@link guide/interpolation interpolation} in the value of the `style`
41823 * attribute, when using the `ngStyle` directive on the same element.
41824 * See {@link guide/interpolation#known-issues here} for more info.
41825 *
41826 * @element ANY
41827 * @param {expression} ngStyle
41828 *
41829 * {@link guide/expression Expression} which evals to an
41830 * object whose keys are CSS style names and values are corresponding values for those CSS
41831 * keys.
41832 *
41833 * Since some CSS style names are not valid keys for an object, they must be quoted.
41834 * See the 'background-color' style in the example below.
41835 *
41836 * @example
41837   <example name="ng-style">
41838     <file name="index.html">
41839        <input type="button" value="set color" ng-click="myStyle={color:'red'}">
41840        <input type="button" value="set background" ng-click="myStyle={'background-color':'blue'}">
41841        <input type="button" value="clear" ng-click="myStyle={}">
41842        <br/>
41843        <span ng-style="myStyle">Sample Text</span>
41844        <pre>myStyle={{myStyle}}</pre>
41845     </file>
41846     <file name="style.css">
41847       span {
41848         color: black;
41849       }
41850     </file>
41851     <file name="protractor.js" type="protractor">
41852       var colorSpan = element(by.css('span'));
41853
41854       it('should check ng-style', function() {
41855         expect(colorSpan.getCssValue('color')).toBe('rgba(0, 0, 0, 1)');
41856         element(by.css('input[value=\'set color\']')).click();
41857         expect(colorSpan.getCssValue('color')).toBe('rgba(255, 0, 0, 1)');
41858         element(by.css('input[value=clear]')).click();
41859         expect(colorSpan.getCssValue('color')).toBe('rgba(0, 0, 0, 1)');
41860       });
41861     </file>
41862   </example>
41863 */
41864var ngStyleDirective = ngDirective(function(scope, element, attr) {
41865  scope.$watch(attr.ngStyle, function ngStyleWatchAction(newStyles, oldStyles) {
41866    if (oldStyles && (newStyles !== oldStyles)) {
41867      forEach(oldStyles, function(val, style) { element.css(style, '');});
41868    }
41869    if (newStyles) element.css(newStyles);
41870  }, true
vendor: 15,211 bytes, lines 41870-42259
41870);
41871});
41872
41873/**
41874 * @ngdoc directive
41875 * @name ngSwitch
41876 * @restrict EA
41877 *
41878 * @description
41879 * The `ngSwitch` directive is used to conditionally swap DOM structure on your template based on a scope expression.
41880 * Elements within `ngSwitch` but without `ngSwitchWhen` or `ngSwitchDefault` directives will be preserved at the location
41881 * as specified in the template.
41882 *
41883 * The directive itself works similar to ngInclude, however, instead of downloading template code (or loading it
41884 * from the template cache), `ngSwitch` simply chooses one of the nested elements and makes it visible based on which element
41885 * matches the value obtained from the evaluated expression. In other words, you define a container element
41886 * (where you place the directive), place an expression on the **`on="..."` attribute**
41887 * (or the **`ng-switch="..."` attribute**), define any inner elements inside of the directive and place
41888 * a when attribute per element. The when attribute is used to inform ngSwitch which element to display when the on
41889 * expression is evaluated. If a matching expression is not found via a when attribute then an element with the default
41890 * attribute is displayed.
41891 *
41892 * <div class="alert alert-info">
41893 * Be aware that the attribute values to match against cannot be expressions. They are interpreted
41894 * as literal string values to match against.
41895 * For example, **`ng-switch-when="someVal"`** will match against the string `"someVal"` not against the
41896 * value of the expression `$scope.someVal`.
41897 * </div>
41898
41899 * @animations
41900 * | Animation                        | Occurs                              |
41901 * |----------------------------------|-------------------------------------|
41902 * | {@link ng.$animate#enter enter}  | after the ngSwitch contents change and the matched child element is placed inside the container |
41903 * | {@link ng.$animate#leave leave}  | after the ngSwitch contents change and just before the former contents are removed from the DOM |
41904 *
41905 * @usage
41906 *
41907 * ```
41908 * <ANY ng-switch="expression">
41909 *   <ANY ng-switch-when="matchValue1">...</ANY>
41910 *   <ANY ng-switch-when="matchValue2">...</ANY>
41911 *   <ANY ng-switch-default>...</ANY>
41912 * </ANY>
41913 * ```
41914 *
41915 *
41916 * @scope
41917 * @priority 1200
41918 * @param {*} ngSwitch|on expression to match against <code>ng-switch-when</code>.
41919 * On child elements add:
41920 *
41921 * * `ngSwitchWhen`: the case statement to match against. If match then this
41922 *   case will be displayed. If the same match appears multiple times, all the
41923 *   elements will be displayed. It is possible to associate multiple values to
41924 *   the same `ngSwitchWhen` by defining the optional attribute
41925 *   `ngSwitchWhenSeparator`. The separator will be used to split the value of
41926 *   the `ngSwitchWhen` attribute into multiple tokens, and the element will show
41927 *   if any of the `ngSwitch` evaluates to any of these tokens.
41928 * * `ngSwitchDefault`: the default case when no other case match. If there
41929 *   are multiple default cases, all of them will be displayed when no other
41930 *   case match.
41931 *
41932 *
41933 * @example
41934  <example module="switchExample" deps="angular-animate.js" animations="true" name="ng-switch">
41935    <file name="index.html">
41936      <div ng-controller="ExampleController">
41937        <select ng-model="selection" ng-options="item for item in items">
41938        </select>
41939        <code>selection={{selection}}</code>
41940        <hr/>
41941        <div class="animate-switch-container"
41942          ng-switch on="selection">
41943            <div class="animate-switch" ng-switch-when="settings|options" ng-switch-when-separator="|">Settings Div</div>
41944            <div class="animate-switch" ng-switch-when="home">Home Span</div>
41945            <div class="animate-switch" ng-switch-default>default</div>
41946        </div>
41947      </div>
41948    </file>
41949    <file name="script.js">
41950      angular.module('switchExample', ['ngAnimate'])
41951        .controller('ExampleController', ['$scope', function($scope) {
41952          $scope.items = ['settings', 'home', 'options', 'other'];
41953          $scope.selection = $scope.items[0];
41954        }]);
41955    </file>
41956    <file name="animations.css">
41957      .animate-switch-container {
41958        position:relative;
41959        background:white;
41960        border:1px solid black;
41961        height:40px;
41962        overflow:hidden;
41963      }
41964
41965      .animate-switch {
41966        padding:10px;
41967      }
41968
41969      .animate-switch.ng-animate {
41970        transition:all cubic-bezier(0.250, 0.460, 0.450, 0.940) 0.5s;
41971
41972        position:absolute;
41973        top:0;
41974        left:0;
41975        right:0;
41976        bottom:0;
41977      }
41978
41979      .animate-switch.ng-leave.ng-leave-active,
41980      .animate-switch.ng-enter {
41981        top:-50px;
41982      }
41983      .animate-switch.ng-leave,
41984      .animate-switch.ng-enter.ng-enter-active {
41985        top:0;
41986      }
41987    </file>
41988    <file name="protractor.js" type="protractor">
41989      var switchElem = element(by.css('[ng-switch]'));
41990      var select = element(by.model('selection'));
41991
41992      it('should start in settings', function() {
41993        expect(switchElem.getText()).toMatch(/Settings Div/);
41994      });
41995      it('should change to home', function() {
41996        select.all(by.css('option')).get(1).click();
41997        expect(switchElem.getText()).toMatch(/Home Span/);
41998      });
41999      it('should change to settings via "options"', function() {
42000        select.all(by.css('option')).get(2).click();
42001        expect(switchElem.getText()).toMatch(/Settings Div/);
42002      });
42003      it('should select default', function() {
42004        select.all(by.css('option')).get(3).click();
42005        expect(switchElem.getText()).toMatch(/default/);
42006      });
42007    </file>
42008  </example>
42009 */
42010var ngSwitchDirective = ['$animate', '$compile', function($animate, $compile) {
42011  return {
42012    require: 'ngSwitch',
42013
42014    // asks for $scope to fool the BC controller module
42015    controller: ['$scope', function NgSwitchController() {
42016     this.cases = {};
42017    }],
42018    link: function(scope, element, attr, ngSwitchController) {
42019      var watchExpr = attr.ngSwitch || attr.on,
42020          selectedTranscludes = [],
42021          selectedElements = [],
42022          previousLeaveAnimations = [],
42023          selectedScopes = [];
42024
42025      var spliceFactory = function(array, index) {
42026          return function(response) {
42027            if (response !== false) array.splice(index, 1);
42028          };
42029      };
42030
42031      scope.$watch(watchExpr, function ngSwitchWatchAction(value) {
42032        var i, ii;
42033
42034        // Start with the last, in case the array is modified during the loop
42035        while (previousLeaveAnimations.length) {
42036          $animate.cancel(previousLeaveAnimations.pop());
42037        }
42038
42039        for (i = 0, ii = selectedScopes.length; i < ii; ++i) {
42040          var selected = getBlockNodes(selectedElements[i].clone);
42041          selectedScopes[i].$destroy();
42042          var runner = previousLeaveAnimations[i] = $animate.leave(selected);
42043          runner.done(spliceFactory(previousLeaveAnimations, i));
42044        }
42045
42046        selectedElements.length = 0;
42047        selectedScopes.length = 0;
42048
42049        if ((selectedTranscludes = ngSwitchController.cases['!' + value] || ngSwitchController.cases['?'])) {
42050          forEach(selectedTranscludes, function(selectedTransclude) {
42051            selectedTransclude.transclude(function(caseElement, selectedScope) {
42052              selectedScopes.push(selectedScope);
42053              var anchor = selectedTransclude.element;
42054              caseElement[caseElement.length++] = $compile.$$createComment('end ngSwitchWhen');
42055              var block = { clone: caseElement };
42056
42057              selectedElements.push(block);
42058              $animate.enter(caseElement, anchor.parent(), anchor);
42059            });
42060          });
42061        }
42062      });
42063    }
42064  };
42065}];
42066
42067var ngSwitchWhenDirective = ngDirective({
42068  transclude: 'element',
42069  priority: 1200,
42070  require: '^ngSwitch',
42071  multiElement: true,
42072  link: function(scope, element, attrs, ctrl, $transclude) {
42073
42074    var cases = attrs.ngSwitchWhen.split(attrs.ngSwitchWhenSeparator).sort().filter(
42075      // Filter duplicate cases
42076      function(element, index, array) { return array[index - 1] !== element; }
42077    );
42078
42079    forEach(cases, function(whenCase) {
42080      ctrl.cases['!' + whenCase] = (ctrl.cases['!' + whenCase] || []);
42081      ctrl.cases['!' + whenCase].push({ transclude: $transclude, element: element });
42082    });
42083  }
42084});
42085
42086var ngSwitchDefaultDirective = ngDirective({
42087  transclude: 'element',
42088  priority: 1200,
42089  require: '^ngSwitch',
42090  multiElement: true,
42091  link: function(scope, element, attr, ctrl, $transclude) {
42092    ctrl.cases['?'] = (ctrl.cases['?'] || []);
42093    ctrl.cases['?'].push({ transclude: $transclude, element: element });
42094   }
42095});
42096
42097/**
42098 * @ngdoc directive
42099 * @name ngTransclude
42100 * @restrict EAC
42101 *
42102 * @description
42103 * Directive that marks the insertion point for the transcluded DOM of the nearest parent directive that uses transclusion.
42104 *
42105 * You can specify that you want to insert a named transclusion slot, instead of the default slot, by providing the slot name
42106 * as the value of the `ng-transclude` or `ng-transclude-slot` attribute.
42107 *
42108 * If the transcluded content is not empty (i.e. contains one or more DOM nodes, including whitespace text nodes), any existing
42109 * content of this element will be removed before the transcluded content is inserted.
42110 * If the transcluded content is empty (or only whitespace), the existing content is left intact. This lets you provide fallback
42111 * content in the case that no transcluded content is provided.
42112 *
42113 * @element ANY
42114 *
42115 * @param {string} ngTransclude|ngTranscludeSlot the name of the slot to insert at this point. If this is not provided, is empty
42116 *                                               or its value is the same as the name of the attribute then the default slot is used.
42117 *
42118 * @example
42119 * ### Basic transclusion
42120 * This example demonstrates basic transclusion of content into a component directive.
42121 * <example name="simpleTranscludeExample" module="transcludeExample">
42122 *   <file name="index.html">
42123 *     <script>
42124 *       angular.module('transcludeExample', [])
42125 *        .directive('pane', function(){
42126 *           return {
42127 *             restrict: 'E',
42128 *             transclude: true,
42129 *             scope: { title:'@' },
42130 *             template: '<div style="border: 1px solid black;">' +
42131 *                         '<div style="background-color: gray">{{title}}</div>' +
42132 *                         '<ng-transclude></ng-transclude>' +
42133 *                       '</div>'
42134 *           };
42135 *       })
42136 *       .controller('ExampleController', ['$scope', function($scope) {
42137 *         $scope.title = 'Lorem Ipsum';
42138 *         $scope.text = 'Neque porro quisquam est qui dolorem ipsum quia dolor...';
42139 *       }]);
42140 *     </script>
42141 *     <div ng-controller="ExampleController">
42142 *       <input ng-model="title" aria-label="title"> <br/>
42143 *       <textarea ng-model="text" aria-label="text"></textarea> <br/>
42144 *       <pane title="{{title}}"><span>{{text}}</span></pane>
42145 *     </div>
42146 *   </file>
42147 *   <file name="protractor.js" type="protractor">
42148 *      it('should have transcluded', function() {
42149 *        var titleElement = element(by.model('title'));
42150 *        titleElement.clear();
42151 *        titleElement.sendKeys('TITLE');
42152 *        var textElement = element(by.model('text'));
42153 *        textElement.clear();
42154 *        textElement.sendKeys('TEXT');
42155 *        expect(element(by.binding('title')).getText()).toEqual('TITLE');
42156 *        expect(element(by.binding('text')).getText()).toEqual('TEXT');
42157 *      });
42158 *   </file>
42159 * </example>
42160 *
42161 * @example
42162 * ### Transclude fallback content
42163 * This example shows how to use `NgTransclude` with fallback content, that
42164 * is displayed if no transcluded content is provided.
42165 *
42166 * <example module="transcludeFallbackContentExample" name="ng-transclude">
42167 * <file name="index.html">
42168 * <script>
42169 * angular.module('transcludeFallbackContentExample', [])
42170 * .directive('myButton', function(){
42171 *             return {
42172 *               restrict: 'E',
42173 *               transclude: true,
42174 *               scope: true,
42175 *               template: '<button style="cursor: pointer;">' +
42176 *                           '<ng-transclude>' +
42177 *                             '<b style="color: red;">Button1</b>' +
42178 *                           '</ng-transclude>' +
42179 *                         '</button>'
42180 *             };
42181 *         });
42182 * </script>
42183 * <!-- fallback button content -->
42184 * <my-button id="fallback"></my-button>
42185 * <!-- modified button content -->
42186 * <my-button id="modified">
42187 *   <i style="color: green;">Button2</i>
42188 * </my-button>
42189 * </file>
42190 * <file name="protractor.js" type="protractor">
42191 * it('should have different transclude element content', function() {
42192 *          expect(element(by.id('fallback')).getText()).toBe('Button1');
42193 *          expect(element(by.id('modified')).getText()).toBe('Button2');
42194 *        });
42195 * </file>
42196 * </example>
42197 *
42198 * @example
42199 * ### Multi-slot transclusion
42200 * This example demonstrates using multi-slot transclusion in a component directive.
42201 * <example name="multiSlotTranscludeExample" module="multiSlotTranscludeExample">
42202 *   <file name="index.html">
42203 *    <style>
42204 *      .title, .footer {
42205 *        background-color: gray
42206 *      }
42207 *    </style>
42208 *    <div ng-controller="ExampleController">
42209 *      <input ng-model="title" aria-label="title"> <br/>
42210 *      <textarea ng-model="text" aria-label="text"></textarea> <br/>
42211 *      <pane>
42212 *        <pane-title><a ng-href="{{link}}">{{title}}</a></pane-title>
42213 *        <pane-body><p>{{text}}</p></pane-body>
42214 *      </pane>
42215 *    </div>
42216 *   </file>
42217 *   <file name="app.js">
42218 *    angular.module('multiSlotTranscludeExample', [])
42219 *     .directive('pane', function() {
42220 *        return {
42221 *          restrict: 'E',
42222 *          transclude: {
42223 *            'title': '?paneTitle',
42224 *            'body': 'paneBody',
42225 *            'footer': '?paneFooter'
42226 *          },
42227 *          template: '<div style="border: 1px solid black;">' +
42228 *                      '<div class="title" ng-transclude="title">Fallback Title</div>' +
42229 *                      '<div ng-transclude="body"></div>' +
42230 *                      '<div class="footer" ng-transclude="footer">Fallback Footer</div>' +
42231 *                    '</div>'
42232 *        };
42233 *    })
42234 *    .controller('ExampleController', ['$scope', function($scope) {
42235 *      $scope.title = 'Lorem Ipsum';
42236 *      $scope.link = 'https://google.com';
42237 *      $scope.text = 'Neque porro quisquam est qui dolorem ipsum quia dolor...';
42238 *    }]);
42239 *   </file>
42240 *   <file name="protractor.js" type="protractor">
42241 *      it('should have transcluded the title and the body', function() {
42242 *        var titleElement = element(by.model('title'));
42243 *        titleElement.clear();
42244 *        titleElement.sendKeys('TITLE');
42245 *        var textElement = element(by.model('text'));
42246 *        textElement.clear();
42247 *        textElement.sendKeys('TEXT');
42248 *        expect(element(by.css('.title')).getText()).toEqual('TITLE');
42249 *        expect(element(by.binding('text')).getText()).toEqual('TEXT');
42250 *        expect(element(by.css('.footer')).getText()).toEqual('Fallback Footer');
42251 *      });
42252 *   </file>
42253 * </example>
42254 */
42255var ngTranscludeMinErr = minErr('ngTransclude');
42256var ngTranscludeDirective = ['$compile', function($compile) {
42257  return {
42258    restrict: 'EAC',
42259    
42259terminal: true,
42260    compile: function ngTranscludeCompile(tElement) {
42261
42262      // Remove and cache any original content to act as a fallback
42263      var fallbackLinkFn = $compile(tElement.contents());
42264      tElement.empty();
42265
42266      return function ngTranscludePostLink($scope, $element, $attrs, controller, $transclude) {
42267
42268        if (!$transclude) {
42269          throw ngTranscludeMinErr('orphan',
42270          'Illegal use of ngTransclude directive in the template! ' +
42271          'No parent directive that requires a transclusion found. ' +
42272          'Element: {0}',
42273          startingTag($element));
42274        }
42275
42276
42277        // If the attribute is of the form: `ng-transclude="ng-transclude"` then treat it like the default
42278        if ($attrs.ngTransclude === $attrs.$attr.ngTransclude) {
42279          $attrs.ngTransclude = '';
42280        }
42281        var slotName = $attrs.ngTransclude || $attrs.ngTranscludeSlot;
42282
42283        // If the slot is required and no transclusion content is provided then this call will throw an error
42284        $transclude(ngTranscludeCloneAttachFn, null, slotName);
42285
vendor: 14,166 bytes, lines 42286-42691
42286        // If the slot is optional and no transclusion content is provided then use the fallback content
42287        if (slotName && !$transclude.isSlotFilled(slotName)) {
42288          useFallbackContent();
42289        }
42290
42291        function ngTranscludeCloneAttachFn(clone, transcludedScope) {
42292          if (clone.length && notWhitespace(clone)) {
42293            $element.append(clone);
42294          } else {
42295            useFallbackContent();
42296            // There is nothing linked against the transcluded scope since no content was available,
42297            // so it should be safe to clean up the generated scope.
42298            transcludedScope.$destroy();
42299          }
42300        }
42301
42302        function useFallbackContent() {
42303          // Since this is the fallback content rather than the transcluded content,
42304          // we link against the scope of this directive rather than the transcluded scope
42305          fallbackLinkFn($scope, function(clone) {
42306            $element.append(clone);
42307          });
42308        }
42309
42310        function notWhitespace(nodes) {
42311          for (var i = 0, ii = nodes.length; i < ii; i++) {
42312            var node = nodes[i];
42313            if (node.nodeType !== NODE_TYPE_TEXT || node.nodeValue.trim()) {
42314              return true;
42315            }
42316          }
42317        }
42318      };
42319    }
42320  };
42321}];
42322
42323/**
42324 * @ngdoc directive
42325 * @name script
42326 * @restrict E
42327 *
42328 * @description
42329 * Load the content of a `<script>` element into {@link ng.$templateCache `$templateCache`}, so that the
42330 * template can be used by {@link ng.directive:ngInclude `ngInclude`},
42331 * {@link ngRoute.directive:ngView `ngView`}, or {@link guide/directive directives}. The type of the
42332 * `<script>` element must be specified as `text/ng-template`, and a cache name for the template must be
42333 * assigned through the element's `id`, which can then be used as a directive's `templateUrl`.
42334 *
42335 * @param {string} type Must be set to `'text/ng-template'`.
42336 * @param {string} id Cache name of the template.
42337 *
42338 * @example
42339  <example  name="script-tag">
42340    <file name="index.html">
42341      <script type="text/ng-template" id="/tpl.html">
42342        Content of the template.
42343      </script>
42344
42345      <a ng-click="currentTpl='/tpl.html'" id="tpl-link">Load inlined template</a>
42346      <div id="tpl-content" ng-include src="currentTpl"></div>
42347    </file>
42348    <file name="protractor.js" type="protractor">
42349      it('should load template defined inside script tag', function() {
42350        element(by.css('#tpl-link')).click();
42351        expect(element(by.css('#tpl-content')).getText()).toMatch(/Content of the template/);
42352      });
42353    </file>
42354  </example>
42355 */
42356var scriptDirective = ['$templateCache', function($templateCache) {
42357  return {
42358    restrict: 'E',
42359    terminal: true,
42360    compile: function(element, attr) {
42361      if (attr.type === 'text/ng-template') {
42362        var templateUrl = attr.id,
42363            text = element[0].text;
42364
42365        $templateCache.put(templateUrl, text);
42366      }
42367    }
42368  };
42369}];
42370
42371/* exported selectDirective, optionDirective */
42372
42373var noopNgModelController = { $setViewValue: noop, $render: noop };
42374
42375function setOptionSelectedStatus(optionEl, value) {
42376  optionEl.prop('selected', value); // needed for IE
42377  /**
42378   * When unselecting an option, setting the property to null / false should be enough
42379   * However, screenreaders might react to the selected attribute instead, see
42380   * https://github.com/angular/angular.js/issues/14419
42381   * Note: "selected" is a boolean attr and will be removed when the "value" arg in attr() is false
42382   * or null
42383   */
42384  optionEl.attr('selected', value);
42385}
42386
42387/**
42388 * @ngdoc type
42389 * @name  select.SelectController
42390 * @description
42391 * The controller for the `<select>` directive. This provides support for reading
42392 * and writing the selected value(s) of the control and also coordinates dynamically
42393 * added `<option>` elements, perhaps by an `ngRepeat` directive.
42394 */
42395var SelectController =
42396        ['$element', '$scope', /** @this */ function($element, $scope) {
42397
42398  var self = this,
42399      optionsMap = new NgMap();
42400
42401  self.selectValueMap = {}; // Keys are the hashed values, values the original values
42402
42403  // If the ngModel doesn't get provided then provide a dummy noop version to prevent errors
42404  self.ngModelCtrl = noopNgModelController;
42405  self.multiple = false;
42406
42407  // The "unknown" option is one that is prepended to the list if the viewValue
42408  // does not match any of the options. When it is rendered the value of the unknown
42409  // option is '? XXX ?' where XXX is the hashKey of the value that is not known.
42410  //
42411  // We can't just jqLite('<option>') since jqLite is not smart enough
42412  // to create it in <select> and IE barfs otherwise.
42413  self.unknownOption = jqLite(window.document.createElement('option'));
42414
42415  // The empty option is an option with the value '' that te application developer can
42416  // provide inside the select. When the model changes to a value that doesn't match an option,
42417  // it is selected - so if an empty option is provided, no unknown option is generated.
42418  // However, the empty option is not removed when the model matches an option. It is always selectable
42419  // and indicates that a "null" selection has been made.
42420  self.hasEmptyOption = false;
42421  self.emptyOption = undefined;
42422
42423  self.renderUnknownOption = function(val) {
42424    var unknownVal = self.generateUnknownOptionValue(val);
42425    self.unknownOption.val(unknownVal);
42426    $element.prepend(self.unknownOption);
42427    setOptionSelectedStatus(self.unknownOption, true);
42428    $element.val(unknownVal);
42429  };
42430
42431  self.updateUnknownOption = function(val) {
42432    var unknownVal = self.generateUnknownOptionValue(val);
42433    self.unknownOption.val(unknownVal);
42434    setOptionSelectedStatus(self.unknownOption, true);
42435    $element.val(unknownVal);
42436  };
42437
42438  self.generateUnknownOptionValue = function(val) {
42439    return '? ' + hashKey(val) + ' ?';
42440  };
42441
42442  self.removeUnknownOption = function() {
42443    if (self.unknownOption.parent()) self.unknownOption.remove();
42444  };
42445
42446  self.selectEmptyOption = function() {
42447    if (self.emptyOption) {
42448      $element.val('');
42449      setOptionSelectedStatus(self.emptyOption, true);
42450    }
42451  };
42452
42453  self.unselectEmptyOption = function() {
42454    if (self.hasEmptyOption) {
42455      self.emptyOption.removeAttr('selected');
42456    }
42457  };
42458
42459  $scope.$on('$destroy', function() {
42460    // disable unknown option so that we don't do work when the whole select is being destroyed
42461    self.renderUnknownOption = noop;
42462  });
42463
42464  // Read the value of the select control, the implementation of this changes depending
42465  // upon whether the select can have multiple values and whether ngOptions is at work.
42466  self.readValue = function readSingleValue() {
42467    var val = $element.val();
42468    // ngValue added option values are stored in the selectValueMap, normal interpolations are not
42469    var realVal = val in self.selectValueMap ? self.selectValueMap[val] : val;
42470
42471    if (self.hasOption(realVal)) {
42472      return realVal;
42473    }
42474
42475    return null;
42476  };
42477
42478
42479  // Write the value to the select control, the implementation of this changes depending
42480  // upon whether the select can have multiple values and whether ngOptions is at work.
42481  self.writeValue = function writeSingleValue(value) {
42482    // Make sure to remove the selected attribute from the previously selected option
42483    // Otherwise, screen readers might get confused
42484    var currentlySelectedOption = $element[0].options[$element[0].selectedIndex];
42485    if (currentlySelectedOption) setOptionSelectedStatus(jqLite(currentlySelectedOption), false);
42486
42487    if (self.hasOption(value)) {
42488      self.removeUnknownOption();
42489
42490      var hashedVal = hashKey(value);
42491      $element.val(hashedVal in self.selectValueMap ? hashedVal : value);
42492
42493      // Set selected attribute and property on selected option for screen readers
42494      var selectedOption = $element[0].options[$element[0].selectedIndex];
42495      setOptionSelectedStatus(jqLite(selectedOption), true);
42496    } else {
42497      if (value == null && self.emptyOption) {
42498        self.removeUnknownOption();
42499        self.selectEmptyOption();
42500      } else if (self.unknownOption.parent().length) {
42501        self.updateUnknownOption(value);
42502      } else {
42503        self.renderUnknownOption(value);
42504      }
42505    }
42506  };
42507
42508
42509  // Tell the select control that an option, with the given value, has been added
42510  self.addOption = function(value, element) {
42511    // Skip comment nodes, as they only pollute the `optionsMap`
42512    if (element[0].nodeType === NODE_TYPE_COMMENT) return;
42513
42514    assertNotHasOwnProperty(value, '"option value"');
42515    if (value === '') {
42516      self.hasEmptyOption = true;
42517      self.emptyOption = element;
42518    }
42519    var count = optionsMap.get(value) || 0;
42520    optionsMap.set(value, count + 1);
42521    // Only render at the end of a digest. This improves render performance when many options
42522    // are added during a digest and ensures all relevant options are correctly marked as selected
42523    scheduleRender();
42524  };
42525
42526  // Tell the select control that an option, with the given value, has been removed
42527  self.removeOption = function(value) {
42528    var count = optionsMap.get(value);
42529    if (count) {
42530      if (count === 1) {
42531        optionsMap.delete(value);
42532        if (value === '') {
42533          self.hasEmptyOption = false;
42534          self.emptyOption = undefined;
42535        }
42536      } else {
42537        optionsMap.set(value, count - 1);
42538      }
42539    }
42540  };
42541
42542  // Check whether the select control has an option matching the given value
42543  self.hasOption = function(value) {
42544    return !!optionsMap.get(value);
42545  };
42546
42547
42548  var renderScheduled = false;
42549  function scheduleRender() {
42550    if (renderScheduled) return;
42551    renderScheduled = true;
42552    $scope.$$postDigest(function() {
42553      renderScheduled = false;
42554      self.ngModelCtrl.$render();
42555    });
42556  }
42557
42558  var updateScheduled = false;
42559  function scheduleViewValueUpdate(renderAfter) {
42560    if (updateScheduled) return;
42561
42562    updateScheduled = true;
42563
42564    $scope.$$postDigest(function() {
42565      if ($scope.$$destroyed) return;
42566
42567      updateScheduled = false;
42568      self.ngModelCtrl.$setViewValue(self.readValue());
42569      if (renderAfter) self.ngModelCtrl.$render();
42570    });
42571  }
42572
42573
42574  self.registerOption = function(optionScope, optionElement, optionAttrs, interpolateValueFn, interpolateTextFn) {
42575
42576    if (optionAttrs.$attr.ngValue) {
42577      // The value attribute is set by ngValue
42578      var oldVal, hashedVal = NaN;
42579      optionAttrs.$observe('value', function valueAttributeObserveAction(newVal) {
42580
42581        var removal;
42582        var previouslySelected = optionElement.prop('selected');
42583
42584        if (isDefined(hashedVal)) {
42585          self.removeOption(oldVal);
42586          delete self.selectValueMap[hashedVal];
42587          removal = true;
42588        }
42589
42590        hashedVal = hashKey(newVal);
42591        oldVal = newVal;
42592        self.selectValueMap[hashedVal] = newVal;
42593        self.addOption(newVal, optionElement);
42594        // Set the attribute directly instead of using optionAttrs.$set - this stops the observer
42595        // from firing a second time. Other $observers on value will also get the result of the
42596        // ngValue expression, not the hashed value
42597        optionElement.attr('value', hashedVal);
42598
42599        if (removal && previouslySelected) {
42600          scheduleViewValueUpdate();
42601        }
42602
42603      });
42604    } else if (interpolateValueFn) {
42605      // The value attribute is interpolated
42606      optionAttrs.$observe('value', function valueAttributeObserveAction(newVal) {
42607        // This method is overwritten in ngOptions and has side-effects!
42608        self.readValue();
42609
42610        var removal;
42611        var previouslySelected = optionElement.prop('selected');
42612
42613        if (isDefined(oldVal)) {
42614          self.removeOption(oldVal);
42615          removal = true;
42616        }
42617        oldVal = newVal;
42618        self.addOption(newVal, optionElement);
42619
42620        if (removal && previouslySelected) {
42621          scheduleViewValueUpdate();
42622        }
42623      });
42624    } else if (interpolateTextFn) {
42625      // The text content is interpolated
42626      optionScope.$watch(interpolateTextFn, function interpolateWatchAction(newVal, oldVal) {
42627        optionAttrs.$set('value', newVal);
42628        var previouslySelected = optionElement.prop('selected');
42629        if (oldVal !== newVal) {
42630          self.removeOption(oldVal);
42631        }
42632        self.addOption(newVal, optionElement);
42633
42634        if (oldVal && previouslySelected) {
42635          scheduleViewValueUpdate();
42636        }
42637      });
42638    } else {
42639      // The value attribute is static
42640      self.addOption(optionAttrs.value, optionElement);
42641    }
42642
42643
42644    optionAttrs.$observe('disabled', function(newVal) {
42645
42646      // Since model updates will also select disabled options (like ngOptions),
42647      // we only have to handle options becoming disabled, not enabled
42648
42649      if (newVal === 'true' || newVal && optionElement.prop('selected')) {
42650        if (self.multiple) {
42651          scheduleViewValueUpdate(true);
42652        } else {
42653          self.ngModelCtrl.$setViewValue(null);
42654          self.ngModelCtrl.$render();
42655        }
42656      }
42657    });
42658
42659    optionElement.on('$destroy', function() {
42660      var currentValue = self.readValue();
42661      var removeValue = optionAttrs.value;
42662
42663      self.removeOption(removeValue);
42664      scheduleRender();
42665
42666      if (self.multiple && currentValue && currentValue.indexOf(removeValue) !== -1 ||
42667          currentValue === removeValue
42668      ) {
42669        // When multiple (selected) options are destroyed at the same time, we don't want
42670        // to run a model update for each of them. Instead, run a single update in the $$postDigest
42671        scheduleViewValueUpdate(true);
42672      }
42673    });
42674  };
42675}];
42676
42677/**
42678 * @ngdoc directive
42679 * @name select
42680 * @restrict E
42681 *
42682 * @description
42683 * HTML `select` element with angular data-binding.
42684 *
42685 * The `select` directive is used together with {@link ngModel `ngModel`} to provide data-binding
42686 * between the scope and the `<select>` control (including setting default values).
42687 * It also handles dynamic `<option>` elements, which can be added using the {@link ngRepeat `ngRepeat}` or
42688 * {@link ngOptions `ngOptions`} directives.
42689 *
42690 * When an item in the `<select>` menu is selected, the value of the selected option will be bound
42691 * to the model identified by the `ngModel` directive. With static or repeated o
42691ptions, this is
42692 * the content of the `value` attribute or the textContent of the `<option>`, if the value attribute is missing.
42693 * Value and textContent can be interpolated.
42694 *
42695 * ## Matching model and option values
42696 *
42697 * In general, the match between the model and an option is evaluated by strictly comparing the model
42698 * value against the value of the available options.
42699 *
42700 * If you are setting the option value with the option's `value` attribute, or textContent, the
42701 * value will always be a `string` which means that the model value must also be a string.
42702 * Otherwise the `select` directive cannot match them correctly.
42703 *
42704 * To bind the model to a non-string value, you can use one of the following strategies:
42705 * - the {@link ng.ngOptions `ngOptions`} directive
42706 *   ({@link ng.select#using-select-with-ngoptions-and-setting-a-default-value})
42707 * - the {@link ng.ngValue `ngValue`} directive, which allows arbitrary expressions to be
42708 *   option values ({@link ng.select#using-ngvalue-to-bind-the-model-to-an-array-of-objects Example})
42709 * - model $parsers / $formatters to convert the string value
42710 *   ({@link ng.select#binding-select-to-a-non-string-value-via-ngmodel-parsing-formatting Example})
42711 *
42712 * If the viewValue of `ngModel` does not match any of the options, then the control
42713 * will automatically add an "unknown" option, which it then removes when the mismatch is resolved.
42714 *
42715 * Optionally, a single hard-coded `<option>` element, with the value set to an empty string, can
42716 * be nested into the `<select>` element. This element will then represent the `null` or "not selected"
42717 * option. See example below for demonstration.
42718 *
42719 * ## Choosing between `ngRepeat` and `ngOptions`
42720 *
42721 * In many cases, `ngRepeat` can be used on `<option>` elements instead of {@link ng.directive:ngOptions
42722 * ngOptions} to achieve a similar result. However, `ngOptions` provides some benefits:
42723 * - more flexibility in how the `<select>`'s model is assigned via the `select` **`as`** part of the
42724 * comprehension expression
42725 * - reduced memory consumption by not creating a new scope for each repeated instance
42726 * - increased render speed by creating the options in a documentFragment instead of individually
42727 *
42728 * Specifically, select with repeated options slows down significantly starting at 2000 options in
42729 * Chrome and Internet Explorer / Edge.
42730 *
42731 *
42732 * @param {string} ngModel Assignable angular expression to data-bind to.
42733 * @param {string=} name Property name of the form under which the control is published.
42734 * @param {string=} multiple Allows multiple options to be selected. The selected values will be
42735 *     bound to the model as an array.
42736 * @param {string=} required Sets `required` validation error key if the value is not entered.
42737 * @param {string=} ngRequired Adds required attribute and required validation constraint to
42738 * the element when the ngRequired expression evaluates to true. Use ngRequired instead of required
42739 * when you want to data-bind to the required attribute.
42740 * @param {string=} ngChange Angular expression to be executed when selected option(s) changes due to user
42741 *    interaction with the select element.
42742 * @param {string=} ngOptions sets the options that the select is populated with and defines what is
42743 * set on the model on selection. See {@link ngOptions `ngOptions`}.
42744 * @param {string=} ngAttrSize sets the size of the select element dynamically. Uses the
42745 * {@link guide/interpolation#-ngattr-for-binding-to-arbitrary-attributes ngAttr} directive.
42746 *
42747 * @example
42748 * ### Simple `select` elements with static options
42749 *
42750 * <example name="static-select" module="staticSelect">
42751 * <file name="index.html">
42752 * <div ng-controller="ExampleController">
42753 *   <form name="myForm">
42754 *     <label for="singleSelect"> Single select: </label><br>
42755 *     <select name="singleSelect" ng-model="data.singleSelect">
42756 *       <option value="option-1">Option 1</option>
42757 *       <option value="option-2">Option 2</option>
42758 *     </select><br>
42759 *
42760 *     <label for="singleSelect"> Single select with "not selected" option and dynamic option values: </label><br>
42761 *     <select name="singleSelect" id="singleSelect" ng-model="data.singleSelect">
42762 *       <option value="">---Please select---</option> <!-- not selected / blank option -->
42763 *       <option value="{{data.option1}}">Option 1</option> <!-- interpolation -->
42764 *       <option value="option-2">Option 2</option>
42765 *     </select><br>
42766 *     <button ng-click="forceUnknownOption()">Force unknown option</button><br>
42767 *     <tt>singleSelect = {{data.singleSelect}}</tt>
42768 *
42769 *     <hr>
42770 *     <label for="multipleSelect"> Multiple select: </label><br>
42771 *     <select name="multipleSelect" id="multipleSelect" ng-model="data.multipleSelect" multiple>
42772 *       <option value="option-1">Option 1</option>
42773 *       <option value="option-2">Option 2</option>
42774 *       <option value="option-3">Option 3</option>
42775 *     </select><br>
42776 *     <tt>multipleSelect = {{data.multipleSelect}}</tt><br/>
42777 *   </form>
42778 * </div>
42779 * </file>
42780 * <file name="app.js">
42781 *  angular.module('staticSelect', [])
42782 *    .controller('ExampleController', ['$scope', function($scope) {
42783 *      $scope.data = {
42784 *       singleSelect: null,
42785 *       multipleSelect: [],
42786 *       option1: 'option-1'
42787 *      };
42788 *
42789 *      $scope.forceUnknownOption = function() {
42790 *        $scope.data.singleSelect = 'nonsense';
42791 *      };
42792 *   }]);
42793 * </file>
42794 *</example>
42795 *
42796 * ### Using `ngRepeat` to generate `select` options
42797 * <example name="select-ngrepeat" module="ngrepeatSelect">
42798 * <file name="index.html">
42799 * <div ng-controller="ExampleController">
42800 *   <form name="myForm">
42801 *     <label for="repeatSelect"> Repeat select: </label>
42802 *     <select name="repeatSelect" id="repeatSelect" ng-model="data.model">
42803 *       <option ng-repeat="option in data.availableOptions" value="{{option.id}}">{{option.name}}</option>
42804 *     </select>
42805 *   </form>
42806 *   <hr>
42807 *   <tt>model = {{data.model}}</tt><br/>
42808 * </div>
42809 * </file>
42810 * <file name="app.js">
42811 *  angular.module('ngrepeatSelect', [])
42812 *    .controller('ExampleController', ['$scope', function($scope) {
42813 *      $scope.data = {
42814 *       model: null,
42815 *       availableOptions: [
42816 *         {id: '1', name: 'Option A'},
42817 *         {id: '2', name: 'Option B'},
42818 *         {id: '3', name: 'Option C'}
42819 *       ]
42820 *      };
42821 *   }]);
42822 * </file>
42823 *</example>
42824 *
42825 * ### Using `ngValue` to bind the model to an array of objects
42826 * <example name="select-ngvalue" module="ngvalueSelect">
42827 * <file name="index.html">
42828 * <div ng-controller="ExampleController">
42829 *   <form name="myForm">
42830 *     <label for="ngvalueselect"> ngvalue select: </label>
42831 *     <select size="6" name="ngvalueselect" ng-model="data.model" multiple>
42832 *       <option ng-repeat="option in data.availableOptions" ng-value="option.value">{{option.name}}</option>
42833 *     </select>
42834 *   </form>
42835 *   <hr>
42836 *   <pre>model = {{data.model | json}}</pre><br/>
42837 * </div>
42838 * </file>
42839 * <file name="app.js">
42840 *  angular.module('ngvalueSelect', [])
42841 *    .controller('ExampleController', ['$scope', function($scope) {
42842 *      $scope.data = {
42843 *       model: null,
42844 *       availableOptions: [
42845           {value: 'myString', name: 'string'},
42846           {value: 1, name: 'integer'},
42847           {value: true, name: 'boolean'},
42848           {value: null, name: 'null'},
42849           {value: {prop: 'value'}, name: 'object'},
42850           {value: ['a'], name: 'array'}
42851 *       ]
42852 *      };
42853 *   }]);
42854 * </file>
42855 *</example>
42856 *
42857 * ### Using `select` with `ngOptions` and setting a default value
42858 * See the {@link ngOptions ngOptions documentation} for more `ngOptions` usage examples.
42859 *
42860 * <example name="select-with-default-values" module="defaultValueSelect">
42861 * <file name="index.html">
42862 * <div ng-controller="ExampleController">
42863 *   <form name="myForm">
42864 *     <label for="mySelect">Make a choice:</label>
42865 *     <select name="mySelect" id="mySelect"
42866 *       ng-options="option.name for option in data.availableOptions track by option.id"
42867 *       ng-model="data.selectedOption"></select>
42868 *   </form>
42869 *   <hr>
42870 *   <tt>option = {{data.selectedOption}}</tt><br/>
42871 * </div>
42872 * </file>
42873 * <file name="app.js">
42874 *  angular.module('defaultValueSelect', [])
42875 *    .controller('ExampleController', ['$scope', function($scope) {
42876 *      $scope.data = {
42877 *       availableOptions: [
42878 *         {id: '1', name: 'Option A'},
42879 *         {id: '2', name: 'Option B'},
42880 *         {id: '3', name: 'Option C'}
42881 *       ],
42882 *       selectedOption: {id: '3', name: 'Option C'} //This sets the default value of the select in the ui
42883 *       };
42884 *   }]);
42885 * </file>
42886 *</example>
42887 *
42888 *
42889 * ### Binding `select` to a non-string value via `ngModel` parsing / formatting
42890 *
42891 * <example name="select-with-non-string-options" module="nonStringSelect">
42892 *   <file name="index.html">
42893 *     <select ng-model="model.id" convert-to-number>
42894 *       <option value="0">Zero</option>
42895 *       <option value="1">One</option>
42896 *       <option value="2">Two</option>
42897 *     </select>
42898 *     {{ model }}
42899 *   </file>
42900 *   <file name="app.js">
42901 *     angular.module('nonStringSelect', [])
42902 *       .run(function($rootScope) {
42903 *         $rootScope.model = { id: 2 };
42904 *       })
42905 *       .directive('convertToNumber', function() {
42906 *         return {
42907 *           require: 'ngModel',
42908 *           link: function(scope, element, attrs, ngModel) {
42909 *             ngModel.$parsers.push(function(val) {
42910 *               return parseInt(val, 10);
42911 *             });
42912 *             ngModel.$formatters.push(function(val) {
42913 *               return '' + val;
42914 *             });
42915 *           }
42916 *         };
42917 *       });
42918 *   </file>
42919 *   <file name="protractor.js" type="protractor">
42920 *     it('should initialize to model', function() {
42921 *       expect(element(by.model('model.id')).$('option:checked').getText()).toEqual('Two');
42922 *     });
42923 *   </file>
42924 * </example>
42925 *
42926 */
42927var selectDirective = function() {
42928
42929  return {
42930    restrict: 'E',
42931    require: ['select', '?ngModel'],
42932    controller: SelectController,
42933    priority: 1,
42934    link: {
42935      pre: selectPreLink,
42936      post: selectPostLink
42937    }
42938  };
42939
42940  function selectPreLink(scope, element, attr, ctrls) {
42941
42942      var selectCtrl = ctrls[0];
42943      var ngModelCtrl = ctrls[1];
42944
42945      // if ngModel is not defined, we don't need to do anything but set the registerOption
42946      // function to noop, so options don't get added internally
42947      if (!ngModelCtrl) {
42948        selectCtrl.registerOption = noop;
42949        return;
42950      }
42951
42952
42953      selectCtrl.ngModelCtrl = ngModelCtrl;
42954
42955      // When the selected item(s) changes we delegate getting the value of the select control
42956      // to the `readValue` method, which can be changed if the select can have multiple
42957      // selected values or if the options are being generated by `ngOptions`
42958      element.on('change', function() {
42959        selectCtrl.removeUnknownOption();
42960        scope.$apply(function() {
42961          ngModelCtrl.$setViewValue(selectCtrl.readValue());
42962        });
42963      });
42964
42965      // If the select allows multiple values then we need to modify how we read and write
42966      // values from and to the control; also what it means for the value to be empty and
42967      // we have to add an extra watch since ngModel doesn't work well with arrays - it
42968      // doesn't trigger rendering if only an item in the array changes.
42969      if (attr.multiple) {
42970        selectCtrl.multiple = true;
42971
42972        // Read value now needs to check each option to see if it is selected
42973        selectCtrl.readValue = function readMultipleValue() {
42974          var array = [];
42975          forEach(element.find('option'), function(option) {
42976            if (option.selected && !option.disabled) {
42977              var val = option.value;
42978              array.push(val in selectCtrl.selectValueMap ? selectCtrl.selectValueMap[val] : val);
42979            }
42980          });
42981          return array;
42982        };
42983
42984        // Write value now needs to set the selected property of each matching option
42985        selectCtrl.writeValue = function writeMultipleValue(value) {
vendor: 5,037 bytes, lines 42986-43102
42986          forEach(element.find('option'), function(option) {
42987            var shouldBeSelected = !!value && (includes(value, option.value) ||
42988                                               includes(value, selectCtrl.selectValueMap[option.value]));
42989            var currentlySelected = option.selected;
42990
42991            // IE and Edge, adding options to the selection via shift+click/UP/DOWN,
42992            // will de-select already selected options if "selected" on those options was set
42993            // more than once (i.e. when the options were already selected)
42994            // So we only modify the selected property if neccessary.
42995            // Note: this behavior cannot be replicated via unit tests because it only shows in the
42996            // actual user interface.
42997            if (shouldBeSelected !== currentlySelected) {
42998              setOptionSelectedStatus(jqLite(option), shouldBeSelected);
42999            }
43000
43001          });
43002        };
43003
43004        // we have to do it on each watch since ngModel watches reference, but
43005        // we need to work of an array, so we need to see if anything was inserted/removed
43006        var lastView, lastViewRef = NaN;
43007        scope.$watch(function selectMultipleWatch() {
43008          if (lastViewRef === ngModelCtrl.$viewValue && !equals(lastView, ngModelCtrl.$viewValue)) {
43009            lastView = shallowCopy(ngModelCtrl.$viewValue);
43010            ngModelCtrl.$render();
43011          }
43012          lastViewRef = ngModelCtrl.$viewValue;
43013        });
43014
43015        // If we are a multiple select then value is now a collection
43016        // so the meaning of $isEmpty changes
43017        ngModelCtrl.$isEmpty = function(value) {
43018          return !value || value.length === 0;
43019        };
43020
43021      }
43022    }
43023
43024    function selectPostLink(scope, element, attrs, ctrls) {
43025      // if ngModel is not defined, we don't need to do anything
43026      var ngModelCtrl = ctrls[1];
43027      if (!ngModelCtrl) return;
43028
43029      var selectCtrl = ctrls[0];
43030
43031      // We delegate rendering to the `writeValue` method, which can be changed
43032      // if the select can have multiple selected values or if the options are being
43033      // generated by `ngOptions`.
43034      // This must be done in the postLink fn to prevent $render to be called before
43035      // all nodes have been linked correctly.
43036      ngModelCtrl.$render = function() {
43037        selectCtrl.writeValue(ngModelCtrl.$viewValue);
43038      };
43039    }
43040};
43041
43042
43043// The option directive is purely designed to communicate the existence (or lack of)
43044// of dynamically created (and destroyed) option elements to their containing select
43045// directive via its controller.
43046var optionDirective = ['$interpolate', function($interpolate) {
43047  return {
43048    restrict: 'E',
43049    priority: 100,
43050    compile: function(element, attr) {
43051      var interpolateValueFn, interpolateTextFn;
43052
43053      if (isDefined(attr.ngValue)) {
43054        // Will be handled by registerOption
43055      } else if (isDefined(attr.value)) {
43056        // If the value attribute is defined, check if it contains an interpolation
43057        interpolateValueFn = $interpolate(attr.value, true);
43058      } else {
43059        // If the value attribute is not defined then we fall back to the
43060        // text content of the option element, which may be interpolated
43061        interpolateTextFn = $interpolate(element.text(), true);
43062        if (!interpolateTextFn) {
43063          attr.$set('value', element.text());
43064        }
43065      }
43066
43067      return function(scope, element, attr) {
43068        // This is an optimization over using ^^ since we don't want to have to search
43069        // all the way to the root of the DOM for every single option element
43070        var selectCtrlName = '$selectController',
43071            parent = element.parent(),
43072            selectCtrl = parent.data(selectCtrlName) ||
43073              parent.parent().data(selectCtrlName); // in case we are in optgroup
43074
43075        if (selectCtrl) {
43076          selectCtrl.registerOption(scope, element, attr, interpolateValueFn, interpolateTextFn);
43077        }
43078      };
43079    }
43080  };
43081}];
43082
43083/**
43084 * @ngdoc directive
43085 * @name ngRequired
43086 * @restrict A
43087 *
43088 * @description
43089 *
43090 * ngRequired adds the required {@link ngModel.NgModelController#$validators `validator`} to {@link ngModel `ngModel`}.
43091 * It is most often used for {@link input `input`} and {@link select `select`} controls, but can also be
43092 * applied to custom controls.
43093 *
43094 * The directive sets the `required` attribute on the element if the Angular expression inside
43095 * `ngRequired` evaluates to true. A special directive for setting `required` is necessary because we
43096 * cannot use interpolation inside `required`. See the {@link guide/interpolation interpolation guide}
43097 * for more info.
43098 *
43099 * The validator will set the `required` error key to true if the `required` attribute is set and
43100 * calling {@link ngModel.NgModelController#$isEmpty `NgModelController.$isEmpty`} with the
43101 * {@link ngModel.NgModelController#$viewValue `ngModel.$viewValue`} returns `true`. For example, the
43102 * `$isEmpty()` implementation for `input[text]` checks the length of the `$viewValue`. When developing
43103 * custom controls, `$isEmpty()` can be overwritten to account for a $viewValue that is not string-based.
43104 *
43105 * @example
43106 * <example name="ngRequiredDirective" module="ngRequiredExample">
43107 *   <file name="index.html">
43108 *     <script>
43109 *       angular.module('ngRequiredExample', [])
43110 *         .controller('ExampleController', ['$scope', function($scope) {
43111 *           $scope.required = true;
43112 *         }]);
43113 *     </script>
43114 *     <div ng-controller="ExampleController">
43115 *       <form name="form">
43116 *         <label for="required">Toggle required: </label>
43117 *         <input type="checkbox" ng-model="required" id="required" />
43118 *         <br>
43119 *         <label for="input">This input must be filled if `required` is true: </label>
43120 *         <input type="text" ng-model="model" id="input" name="input" ng-required="required" /><br>
43121 *         <hr>
43122 *         required error set? = <code>{{form.input.$error.required}}</code><br>
43123 *         model = <code>{{model}}</code>
43124 *       </form>
43125 *     </div>
43126 *   </file>
43127 *   <file name="protractor.js" type="protractor">
43128       var required = element(by.binding('form.input.$error.required'));
43129       var model = element(by.binding('model'));
43130       var input = element(by.id('input'));
43131
43132       it('should set the required error', function() {
43133         expect(required.getText()).toContain('true');
43134
43135         input.sendKeys('123');
43136         expect(required.getText()).not.toContain('true');
43137         expect(model.getText()).toContain('123');
43138       });
43139 *   </file>
43140 * </example>
43141 */
43142var requiredDirective = function() {
43143  return {
43144    restrict: 'A',
43145    require: '?ngModel',
43146    link: function(scope, elm, attr, ctrl) {
43147      if (!ctrl) return;
43148      attr.required = true; // force truthy in case we are on non input element
43149
43150      ctrl.$validators.required = function(modelValue, viewValue) {
43151        return !attr.required || !ctrl.$isEmpty(viewValue);
43152      };
43153
43154      attr.$observe('required', function() {
43155        ctrl.$validate();
43156      });
43157    }
43158  };
43159};
43160
43161/**
43162 * @ngdoc directive
43163 * @name ngPattern
43164 *
43165 * @description
43166 *
43167 * ngPattern adds the pattern {@link ngModel.NgModelController#$validators `validator`} to {@link ngModel `ngModel`}.
43168 * It is most often used for text-based {@link input `input`} controls, but can also be applied to custom text-based controls.
43169 *
43170 * The validator sets the `pattern` error key if the {@link ngModel.NgModelController#$viewValue `ngModel.$viewValue`}
43171 * does not match a RegExp which is obtained by evaluating the Angular expression given in the
43172 * `ngPattern` attribute value:
43173 * * If the expression evaluates to a RegExp object, then this is used directly.
43174 * * If the expression evaluates to a string, then it will be converted to a RegExp after wrapping it
43175 * in `^` and `$` characters. For instance, `"abc"` will be converted to `new RegExp('^abc$')`.
43176 *
43177 * <div class="alert alert-info">
43178 * **Note:** Avoid using the `g` flag on the RegExp, as it will cause each successive search to
43179 * start at the index of the last search's match, thus not taking the whole input value into
43180 * account.
43181 * </div>
43182 *
43183 * <div class="alert alert-info">
43184 * **Note:** This directive is also added when the plain `pattern` attribute is used, with two
43185 * differences:
43186 * <ol>
43187 *   <li>
43188 *     `ngPattern` does not set the `pattern` attribute and therefore HTML5 constraint validation is
43189 *     not available.
43190 *   </li>
43191 *   <li>
43192 *     The `ngPattern` attribute must be an expression, while the `pattern` value must be
43193 *     interpolated.
43194 *   </li>
43195 * </ol>
43196 * </div>
43197 *
43198 * @example
43199 * <example name="ngPatternDirective" module="ngPatternExample">
43200 *   <file name="index.html">
43201 *     <script>
43202 *       angular.module('ngPatternExample', [])
43203 *         .controller('ExampleController', ['$scope', function($scope) {
43204 *           $scope.regex = '\\d+';
43205 *         }]);
43206 *     </script>
43207 *     <div ng-controller="ExampleController">
43208 *       <form name="form">
43209 *         <label for="regex">Set a pattern (regex string): </label>
43210 *         <input type="text" ng-model="regex" id="regex" />
43211 *         <br>
43212 *         <label for="input">This input is restricted by the current pattern: </label>
43213 *         <input type="text" ng-model="model" id="input" name="input" ng-pattern="regex" /><br>
43214 *         <hr>
43215 *         input valid? = <code>{{form.input.$valid}}</code><br>
43216 *         model = <code>{{model}}</code>
43217 *       </form>
43218 *     </div>
43219 *   </file>
43220 *   <file name="protractor.js" type="protractor">
43221       var model = element(by.binding('model'));
43222       var input = element(by.id('input'));
43223
43224       it('should validate the input with the default pattern', function() {
43225         input.sendKeys('aaa');
43226         expect(model.getText()).not.toContain('aaa');
43227
43228         input.clear().then(function() {
43229           input.sendKeys('123');
43230           expect(model.getText()).toContain('123');
43231         });
43232       });
43233 *   </file>
43234 * </example>
43235 */
43236var patternDirective = function() {
43237  return {
43238    restrict: 'A',
43239    require: '?ngModel',
43240    link: function(scope, elm, attr, ctrl) {
43241      if (!ctrl) return;
43242
43243      var regexp, patternExp = attr.ngPattern || attr.pattern;
43244      attr.$observe('pattern', function(regex) {
43245        if (isString(regex) && regex.length > 0) {
43246          regex = new RegExp('^' + regex + '$');
43247        }
43248
43249        if (regex && !regex.test) {
43250          throw minErr('ngPattern')('noregexp',
43251            'Expected {0} to be a RegExp but was {1}. Element: {2}', patternExp,
43252            regex, startingTag(elm));
43253        }
43254
43255        regexp = regex || undefined;
43256        ctrl.$validate();
43257      });
43258
43259      ctrl.$validators.pattern = function(modelValue, viewValue) {
43260        // HTML5 pattern constraint validates the input value, so we validate the viewValue
43261        return ctrl.$isEmpty(viewValue) || isUndefined(regexp) || regexp.test(viewValue);
43262      };
43263    }
43264  };
43265};
43266
43267/**
43268 * @ngdoc directive
43269 * @name ngMaxlength
43270 *
43271 * @description
43272 *
43273 * ngMaxlength adds the maxlength {@link ngModel.NgModelController#$validators `validator`} to {@link ngModel `ngModel`}.
43274 * It is most often used for text-based {@link input `input`} controls, but can also be applied to custom text-based controls.
43275 *
43276 * The validator sets the `maxlength` error key if the {@link ngModel.NgModelController#$viewValue `ngModel.$viewValue`}
43277 * is longer than the integer obtained by evaluating the Angular expression given in the
43278 * `ngMaxlength` attribute value.
43279 *
43280 * <div class="alert alert-info">
43281 * **Note:** This directive is also added when the plain `maxlength` attribute is used, with two
43282 * differences:
43283 * <ol>
43284 *   <li>
43285 *     `ngMaxlength` does not set the `maxlength` attribute and therefore HTML5 constraint
43286 *     validation is not available.
43287 *   </li>
43288 *   <li>
43289 *     The `ngMaxlength` attribute must be an expression, while the `maxlength` value must be
43290 *     interpolated.
43291 *   </li>
43292 * </ol>
43293 * </div>
43294 *
43295 * @example
43296 * <example name="ngMaxlengthDirective" module="ngMaxlengthExample">
43297 *   <file name="index.html">
43298 *     <script>
43299 *       angular.module('ngMaxlengthExample', [])
43300 *         .controller('ExampleController', ['$scope', function($scope) {
43301 *           $scope.maxlength = 5;
43302 *         }]);
43303 *     </script>
43304 *     <div ng-controller="ExampleController">
43305 *       <form name="form">
43306 *         <label for="maxlength">Set a maxlength: </label>
43307 *         <input type="number" ng-model="maxlength" id="maxlength" />
43308 *         <br>
43309 *         <label for="input">This input is restricted by the current maxlength: </label>
43310 *         <input type="text" ng-model="model" id="input" name="input" ng-maxlength="maxlength" /><br>
43311 *         <hr>
43312 *         input valid? = <code>{{form.input.$valid}}</code><br>
43313 *         model = <code>{{model}}</code>
43314 *       </form>
43315 *     </div>
43316 *   </file>
43317 *   <file name="protractor.js" type="protractor">
43318       var model = element(by.binding('model'));
43319       var input = element(by.id('input'));
43320
43321       it('should validate the input with the default maxlength', function() {
43322         input.sendKeys('abcdef');
43323         expect(model.getText()).not.toContain('abcdef');
43324
43325         input.clear().then(function() {
43326           input.sendKeys('abcde');
43327           expect(model.getText()).toContain('abcde');
43328         });
43329       });
43330 *   </file>
43331 * </example>
43332 */
43333var maxlengthDirective = function() {
43334  return {
43335    restrict: 'A',
43336    require: '?ngModel',
43337    link: function(scope, elm, attr, ctrl) {
43338      if (!ctrl) return;
43339
43340      var maxlength = -1;
43341      attr.$observe('maxlength', function(value) {
43342        var intVal = toInt(value);
43343        maxlength = isNumberNaN(intVal) ? -1 : intVal;
43344        ctrl.$validate();
43345      });
43346      ctrl.$validators.maxlength = function(modelValue, viewValue) {
43347        return (maxlength < 0) || ctrl.$isEmpty(viewValue) || (viewValue.length <= maxlength);
43348      };
43349    }
43350  };
43351};
43352
43353/**
43354 * @ngdoc directive
43355 * @name ngMinlength
43356 *
43357 * @description
43358 *
43359 * ngMinlength adds the minlength {@link ngModel.NgModelController#$validators `validator`} to {@link ngModel `ngModel`}.
43360 * It is most often used for text-based {@link input `input`} controls, but can also be applied to custom text-based controls.
43361 *
43362 * The validator sets the `minlength` error key if the {@link ngModel.NgModelController#$viewValue `ngModel.$viewValue`}
43363 * is shorter than the integer obtained by evaluating the Angular expression given in the
43364 * `ngMinlength` attribute value.
43365 *
43366 * <div class="alert alert-info">
43367 * **Note:** This directive is also added when the plain `minlength` attribute is used, with two
43368 * differences:
43369 * <ol>
43370 *   <li>
43371 *     `ngMinlength` does not set the `minlength` attribute and therefore HTML5 constraint
43372 *     validation is not available.
43373 *   </li>
43374 *   <li>
43375 *     The `ngMinlength` value must be an expression, while the `minlength` value must be
43376 *     interpolated.
43377 *   </li>
43378 * </ol>
43379 * </div>
43380 *
43381 * @example
43382 * <example name="ngMinlengthDirective" module="ngMinlengthExample">
43383 *   <file name="index.html">
43384 *     <script>
43385 *       angular.module('ngMinlengthExample', [])
43386 *         .controller('ExampleController', ['$scope', function($scope) {
43387 *           $scope.minlength = 3;
43388 *         }]);
43389 *     </script>
43390 *     <div ng-controller="ExampleController">
43391 *       <form name="form">
43392 *         <label for="minlength">Set a minlength: </label>
43393 *         <input type="number" ng-model="minlength" id="minlength" />
43394 *         <br>
43395 *         <label for="input">This input is restricted by the current minlength: </label>
43396 *         <input type="text" ng-model="model" id="input" name="input" ng-minlength="minlength" /><br>
43397 *         <hr>
43398 *         input valid? = <code>{{form.input.$valid}}</code><br>
43399 *         model = <code>{{model}}</code>
43400 *       </form>
43401 *     </div>
43402 *   </file>
43403 *   <file name="protractor.js" type="protractor">
43404       var model = element(by.binding('model'));
43405       var input = element(by.id('input'));
43406
43407       it('should validate the input with the default minlength', function() {
43408         input.sendKeys('ab');
43409         expect(model.getText()).not.toContain('ab');
43410
43411         input.sendKeys('abc');
43412         expect(model.getText()).toContain('abc');
43413       });
43414 *   </file>
43415 * </example>
43416 */
43417var minlengthDirective = function() {
43418  return {
43419    restrict: 'A',
43420    require: '?ngModel',
43421    link: function(scope, elm, attr, ctrl) {
43422      if (!ctrl) return;
43423
43424      var minlength = 0;
43425      attr.$observe('minlength', function(value) {
43426        minlength = toInt(value) || 0;
43427        ctrl.$validate();
43428      });
43429      ctrl.$validators.minlength = function(modelValue, viewValue) {
43430        return ctrl.$isEmpty(viewValue) || viewValue.length >= minlength;
43431      };
43432    }
43433  };
43434};
43435
43436if (window.angular.bootstrap) {
43437  // AngularJS is already loaded, so we can return here...
43438  if (window.console) {
43439    console.log('WARNING: Tried to load angular more than once.');
43440  }
43441  return;
43442}
43443
43444// try to bind to jquery now so that one can write jqLite(fn)
43445// but we will rebind on bootstrap again.
43446bindJQuery();
43447
43448publishExternalAPI(angular);
43449
43450angular.module("ngLocale", [], ["$provide", function($provide) {
43451var PLURAL_CATEGORY = {ZERO: "zero", ONE: "one", TWO: "two", FEW: "few", MANY: "many", OTHER: "other"};
43452function getDecimals(n) {
43453  n = n + '';
43454  var i = n.indexOf('.');
43455  return (i == -1) ? 0 : n.length - i - 1;
43456}
43457
43458function getVF(n, opt_precision) {
43459  var v = opt_precision;
43460
43461  if (undefined === v) {
43462    v = Math.min(getDecimals(n), 3);
43463  }
43464
43465  var base = Math.pow(10, v);
43466  var f = ((n * base) | 0) % base;
43467  return {v: v, f: f};
43468}
43469
43470$provide.value("$locale", {
43471  "DATETIME_FORMATS": {
43472    "AMPMS": [
43473      "AM",
43474      "PM"
43475    ],
43476    "DAY": [
43477      "Sunday",
43478      "Monday",
43479      "Tuesday",
43480      "Wednesday",
43481      "Thursday",
43482      "Friday",
43483      "Saturday"
43484    ],
43485    "ERANAMES": [
43486      "Before Christ",
43487      "Anno Domini"
43488    ],
43489    "ERAS": [
43490      "BC",
43491      "AD"
43492    ],
43493    "FIRSTDAYOFWEEK": 6,
43494    "MONTH": [
43495      "January",
43496      "February",
43497      "March",
43498      "April",
43499      "May",
43500      "June",
43501      "July",
43502      "August",
43503      "September",
43504      "October",
43505      "November",
43506      "December"
43507    ],
43508    "SHORTDAY": [
43509      "Sun",
43510      "Mon",
43511      "Tue",
43512      "Wed",
43513      "Thu",
43514      "Fri",
43515      "Sat"
43516    ],
43517    "SHORTMONTH": [
43518      "Jan",
43519      "Feb",
43520      "Mar",
43521      "Apr",
43522      "May",
43523      "Jun",
43524      "Jul",
43525      "Aug",
43526      "Sep",
43527      "Oct",
43528      "Nov",
43529      "Dec"
43530    ],
43531    "STANDALONEMONTH": [
43532      "January",
43533      "February",
43534      "March",
43535      "April",
43536      "May",
43537      "June",
43538      "July",
43539      "August",
43540      "September",
43541      "October",
43542      "November",
43543      "December"
43544    ],
43545    "WEEKENDRANGE": [
43546      5,
43547      6
43548    ],
43549    "fullDate": "EEEE, MMMM d, y",
43550    "longDate": "MMMM d, y",
43551    "medium": "MMM d, y h:mm:ss a",
43552    "mediumDate": "MMM d, y",
43553    "mediumTime": "h:mm:ss a",
43554    "short": "M/d/yy h:mm a",
43555    "shortDate": "M/d/yy",
43556    "shortTime": "h:mm a"
43557  },
43558  "NUMBER_FORMATS": {
43559    "CURRENCY_SYM": "$",
43560    "DECIMAL_SEP": ".",
43561    "GROUP_SEP": ",",
43562    "PATTERNS": [
43563      {
43564        "gSize": 3,
43565        "lgSize": 3,
43566        "maxFrac": 3,
43567        "minFrac": 0,
43568        "minInt": 1,
43569        "negPre": "-",
43570        "negSuf": "",
43571        "posPre": "",
43572        "posSuf": ""
43573      },
43574      {
43575        "gSize": 3,
43576        "lgSize": 3,
43577        "maxFrac": 2,
43578        "minFrac": 2,
43579        "minInt": 1,
43580        "negPre": "-\u00a4",
43581        "negSuf": "",
43582        "posPre": "\u00a4",
43583        "posSuf": ""
43584      }
43585    ]
43586  },
43587  "id": "en-us",
43588  "localeID": "en_US",
43589  "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;}
43590});
43591}]);
43592
43593  jqLite(function() {
43594    angularInit(window.document, bootstrap);
43595  });
43596
43597})(window);
43598
43599!window.angular.$$csp().noInlineStyle && window.angular.element(document.head).prepend('<style type="text/css">@charset "UTF-8";[ng\\:cloak],[ng-cloak],[data-ng-cloak],[x-ng-cloak],.ng-cloak,.x-ng-cloak,.ng-hide:not(.ng-hide-animate){display:none !important;}ng\\:form{display:block;}.ng-animate-shim{visibility:hidden;}.ng-anchor{position:absolute;}</style>');
vendor: 40,181 bytes, lines 43600-44974
43600/*!
43601 * Bootstrap v3.3.7 (http://getbootstrap.com)
43602 * Copyright 2011-2016 Twitter, Inc.
43603 * Licensed under the MIT license
43604 */
43605
43606if (typeof jQuery === 'undefined') {
43607  throw new Error('Bootstrap\'s JavaScript requires jQuery')
43608}
43609
43610+function ($) {
43611  'use strict';
43612  var version = $.fn.jquery.split(' ')[0].split('.')
43613  if ((version[0] < 2 && version[1] < 9) || (version[0] == 1 && version[1] == 9 && version[2] < 1) || (version[0] > 3)) {
43614    throw new Error('Bootstrap\'s JavaScript requires jQuery version 1.9.1 or higher, but lower than version 4')
43615  }
43616}(jQuery);
43617
43618/* ========================================================================
43619 * Bootstrap: transition.js v3.3.7
43620 * http://getbootstrap.com/javascript/#transitions
43621 * ========================================================================
43622 * Copyright 2011-2016 Twitter, Inc.
43623 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
43624 * ======================================================================== */
43625
43626
43627+function ($) {
43628  'use strict';
43629
43630  // CSS TRANSITION SUPPORT (Shoutout: http://www.modernizr.com/)
43631  // ============================================================
43632
43633  function transitionEnd() {
43634    var el = document.createElement('bootstrap')
43635
43636    var transEndEventNames = {
43637      WebkitTransition : 'webkitTransitionEnd',
43638      MozTransition    : 'transitionend',
43639      OTransition      : 'oTransitionEnd otransitionend',
43640      transition       : 'transitionend'
43641    }
43642
43643    for (var name in transEndEventNames) {
43644      if (el.style[name] !== undefined) {
43645        return { end: transEndEventNames[name] }
43646      }
43647    }
43648
43649    return false // explicit for ie8 (  ._.)
43650  }
43651
43652  // http://blog.alexmaccaw.com/css-transitions
43653  $.fn.emulateTransitionEnd = function (duration) {
43654    var called = false
43655    var $el = this
43656    $(this).one('bsTransitionEnd', function () { called = true })
43657    var callback = function () { if (!called) $($el).trigger($.support.transition.end) }
43658    setTimeout(callback, duration)
43659    return this
43660  }
43661
43662  $(function () {
43663    $.support.transition = transitionEnd()
43664
43665    if (!$.support.transition) return
43666
43667    $.event.special.bsTransitionEnd = {
43668      bindType: $.support.transition.end,
43669      delegateType: $.support.transition.end,
43670      handle: function (e) {
43671        if ($(e.target).is(this)) return e.handleObj.handler.apply(this, arguments)
43672      }
43673    }
43674  })
43675
43676}(jQuery);
43677
43678/* ========================================================================
43679 * Bootstrap: alert.js v3.3.7
43680 * http://getbootstrap.com/javascript/#alerts
43681 * ========================================================================
43682 * Copyright 2011-2016 Twitter, Inc.
43683 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
43684 * ======================================================================== */
43685
43686
43687+function ($) {
43688  'use strict';
43689
43690  // ALERT CLASS DEFINITION
43691  // ======================
43692
43693  var dismiss = '[data-dismiss="alert"]'
43694  var Alert   = function (el) {
43695    $(el).on('click', dismiss, this.close)
43696  }
43697
43698  Alert.VERSION = '3.3.7'
43699
43700  Alert.TRANSITION_DURATION = 150
43701
43702  Alert.prototype.close = function (e) {
43703    var $this    = $(this)
43704    var selector = $this.attr('data-target')
43705
43706    if (!selector) {
43707      selector = $this.attr('href')
43708      selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7
43709    }
43710
43711    var $parent = $(selector === '#' ? [] : selector)
43712
43713    if (e) e.preventDefault()
43714
43715    if (!$parent.length) {
43716      $parent = $this.closest('.alert')
43717    }
43718
43719    $parent.trigger(e = $.Event('close.bs.alert'))
43720
43721    if (e.isDefaultPrevented()) return
43722
43723    $parent.removeClass('in')
43724
43725    function removeElement() {
43726      // detach from parent, fire event then clean up data
43727      $parent.detach().trigger('closed.bs.alert').remove()
43728    }
43729
43730    $.support.transition && $parent.hasClass('fade') ?
43731      $parent
43732        .one('bsTransitionEnd', removeElement)
43733        .emulateTransitionEnd(Alert.TRANSITION_DURATION) :
43734      removeElement()
43735  }
43736
43737
43738  // ALERT PLUGIN DEFINITION
43739  // =======================
43740
43741  function Plugin(option) {
43742    return this.each(function () {
43743      var $this = $(this)
43744      var data  = $this.data('bs.alert')
43745
43746      if (!data) $this.data('bs.alert', (data = new Alert(this)))
43747      if (typeof option == 'string') data[option].call($this)
43748    })
43749  }
43750
43751  var old = $.fn.alert
43752
43753  $.fn.alert             = Plugin
43754  $.fn.alert.Constructor = Alert
43755
43756
43757  // ALERT NO CONFLICT
43758  // =================
43759
43760  $.fn.alert.noConflict = function () {
43761    $.fn.alert = old
43762    return this
43763  }
43764
43765
43766  // ALERT DATA-API
43767  // ==============
43768
43769  $(document).on('click.bs.alert.data-api', dismiss, Alert.prototype.close)
43770
43771}(jQuery);
43772
43773/* ========================================================================
43774 * Bootstrap: button.js v3.3.7
43775 * http://getbootstrap.com/javascript/#buttons
43776 * ========================================================================
43777 * Copyright 2011-2016 Twitter, Inc.
43778 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
43779 * ======================================================================== */
43780
43781
43782+function ($) {
43783  'use strict';
43784
43785  // BUTTON PUBLIC CLASS DEFINITION
43786  // ==============================
43787
43788  var Button = function (element, options) {
43789    this.$element  = $(element)
43790    this.options   = $.extend({}, Button.DEFAULTS, options)
43791    this.isLoading = false
43792  }
43793
43794  Button.VERSION  = '3.3.7'
43795
43796  Button.DEFAULTS = {
43797    loadingText: 'loading...'
43798  }
43799
43800  Button.prototype.setState = function (state) {
43801    var d    = 'disabled'
43802    var $el  = this.$element
43803    var val  = $el.is('input') ? 'val' : 'html'
43804    var data = $el.data()
43805
43806    state += 'Text'
43807
43808    if (data.resetText == null) $el.data('resetText', $el[val]())
43809
43810    // push to event loop to allow forms to submit
43811    setTimeout($.proxy(function () {
43812      $el[val](data[state] == null ? this.options[state] : data[state])
43813
43814      if (state == 'loadingText') {
43815        this.isLoading = true
43816        $el.addClass(d).attr(d, d).prop(d, true)
43817      } else if (this.isLoading) {
43818        this.isLoading = false
43819        $el.removeClass(d).removeAttr(d).prop(d, false)
43820      }
43821    }, this), 0)
43822  }
43823
43824  Button.prototype.toggle = function () {
43825    var changed = true
43826    var $parent = this.$element.closest('[data-toggle="buttons"]')
43827
43828    if ($parent.length) {
43829      var $input = this.$element.find('input')
43830      if ($input.prop('type') == 'radio') {
43831        if ($input.prop('checked')) changed = false
43832        $parent.find('.active').removeClass('active')
43833        this.$element.addClass('active')
43834      } else if ($input.prop('type') == 'checkbox') {
43835        if (($input.prop('checked')) !== this.$element.hasClass('active')) changed = false
43836        this.$element.toggleClass('active')
43837      }
43838      $input.prop('checked', this.$element.hasClass('active'))
43839      if (changed) $input.trigger('change')
43840    } else {
43841      this.$element.attr('aria-pressed', !this.$element.hasClass('active'))
43842      this.$element.toggleClass('active')
43843    }
43844  }
43845
43846
43847  // BUTTON PLUGIN DEFINITION
43848  // ========================
43849
43850  function Plugin(option) {
43851    return this.each(function () {
43852      var $this   = $(this)
43853      var data    = $this.data('bs.button')
43854      var options = typeof option == 'object' && option
43855
43856      if (!data) $this.data('bs.button', (data = new Button(this, options)))
43857
43858      if (option == 'toggle') data.toggle()
43859      else if (option) data.setState(option)
43860    })
43861  }
43862
43863  var old = $.fn.button
43864
43865  $.fn.button             = Plugin
43866  $.fn.button.Constructor = Button
43867
43868
43869  // BUTTON NO CONFLICT
43870  // ==================
43871
43872  $.fn.button.noConflict = function () {
43873    $.fn.button = old
43874    return this
43875  }
43876
43877
43878  // BUTTON DATA-API
43879  // ===============
43880
43881  $(document)
43882    .on('click.bs.button.data-api', '[data-toggle^="button"]', function (e) {
43883      var $btn = $(e.target).closest('.btn')
43884      Plugin.call($btn, 'toggle')
43885      if (!($(e.target).is('input[type="radio"], input[type="checkbox"]'))) {
43886        // Prevent double click on radios, and the double selections (so cancellation) on checkboxes
43887        e.preventDefault()
43888        // The target component still receive the focus
43889        if ($btn.is('input,button')) $btn.trigger('focus')
43890        else $btn.find('input:visible,button:visible').first().trigger('focus')
43891      }
43892    })
43893    .on('focus.bs.button.data-api blur.bs.button.data-api', '[data-toggle^="button"]', function (e) {
43894      $(e.target).closest('.btn').toggleClass('focus', /^focus(in)?$/.test(e.type))
43895    })
43896
43897}(jQuery);
43898
43899/* ========================================================================
43900 * Bootstrap: carousel.js v3.3.7
43901 * http://getbootstrap.com/javascript/#carousel
43902 * ========================================================================
43903 * Copyright 2011-2016 Twitter, Inc.
43904 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
43905 * ======================================================================== */
43906
43907
43908+function ($) {
43909  'use strict';
43910
43911  // CAROUSEL CLASS DEFINITION
43912  // =========================
43913
43914  var Carousel = function (element, options) {
43915    this.$element    = $(element)
43916    this.$indicators = this.$element.find('.carousel-indicators')
43917    this.options     = options
43918    this.paused      = null
43919    this.sliding     = null
43920    this.interval    = null
43921    this.$active     = null
43922    this.$items      = null
43923
43924    this.options.keyboard && this.$element.on('keydown.bs.carousel', $.proxy(this.keydown, this))
43925
43926    this.options.pause == 'hover' && !('ontouchstart' in document.documentElement) && this.$element
43927      .on('mouseenter.bs.carousel', $.proxy(this.pause, this))
43928      .on('mouseleave.bs.carousel', $.proxy(this.cycle, this))
43929  }
43930
43931  Carousel.VERSION  = '3.3.7'
43932
43933  Carousel.TRANSITION_DURATION = 600
43934
43935  Carousel.DEFAULTS = {
43936    interval: 5000,
43937    pause: 'hover',
43938    wrap: true,
43939    keyboard: true
43940  }
43941
43942  Carousel.prototype.keydown = function (e) {
43943    if (/input|textarea/i.test(e.target.tagName)) return
43944    switch (e.which) {
43945      case 37: this.prev(); break
43946      case 39: this.next(); break
43947      default: return
43948    }
43949
43950    e.preventDefault()
43951  }
43952
43953  Carousel.prototype.cycle = function (e) {
43954    e || (this.paused = false)
43955
43956    this.interval && clearInterval(this.interval)
43957
43958    this.options.interval
43959      && !this.paused
43960      && (this.interval = setInterval($.proxy(this.next, this), this.options.interval))
43961
43962    return this
43963  }
43964
43965  Carousel.prototype.getItemIndex = function (item) {
43966    this.$items = item.parent().children('.item')
43967    return this.$items.index(item || this.$active)
43968  }
43969
43970  Carousel.prototype.getItemForDirection = function (direction, active) {
43971    var activeIndex = this.getItemIndex(active)
43972    var willWrap = (direction == 'prev' && activeIndex === 0)
43973                || (direction == 'next' && activeIndex == (this.$items.length - 1))
43974    if (willWrap && !this.options.wrap) return active
43975    var delta = direction == 'prev' ? -1 : 1
43976    var itemIndex = (activeIndex + delta) % this.$items.length
43977    return this.$items.eq(itemIndex)
43978  }
43979
43980  Carousel.prototype.to = function (pos) {
43981    var that        = this
43982    var activeIndex = this.getItemIndex(this.$active = this.$element.find('.item.active'))
43983
43984    if (pos > (this.$items.length - 1) || pos < 0) return
43985
43986    if (this.sliding)       return this.$element.one('slid.bs.carousel', function () { that.to(pos) }) // yes, "slid"
43987    if (activeIndex == pos) return this.pause().cycle()
43988
43989    return this.slide(pos > activeIndex ? 'next' : 'prev', this.$items.eq(pos))
43990  }
43991
43992  Carousel.prototype.pause = function (e) {
43993    e || (this.paused = true)
43994
43995    if (this.$element.find('.next, .prev').length && $.support.transition) {
43996      this.$element.trigger($.support.transition.end)
43997      this.cycle(true)
43998    }
43999
44000    this.interval = clearInterval(this.interval)
44001
44002    return this
44003  }
44004
44005  Carousel.prototype.next = function () {
44006    if (this.sliding) return
44007    return this.slide('next')
44008  }
44009
44010  Carousel.prototype.prev = function () {
44011    if (this.sliding) return
44012    return this.slide('prev')
44013  }
44014
44015  Carousel.prototype.slide = function (type, next) {
44016    var $active   = this.$element.find('.item.active')
44017    var $next     = next || this.getItemForDirection(type, $active)
44018    var isCycling = this.interval
44019    var direction = type == 'next' ? 'left' : 'right'
44020    var that      = this
44021
44022    if ($next.hasClass('active')) return (this.sliding = false)
44023
44024    var relatedTarget = $next[0]
44025    var slideEvent = $.Event('slide.bs.carousel', {
44026      relatedTarget: relatedTarget,
44027      direction: direction
44028    })
44029    this.$element.trigger(slideEvent)
44030    if (slideEvent.isDefaultPrevented()) return
44031
44032    this.sliding = true
44033
44034    isCycling && this.pause()
44035
44036    if (this.$indicators.length) {
44037      this.$indicators.find('.active').removeClass('active')
44038      var $nextIndicator = $(this.$indicators.children()[this.getItemIndex($next)])
44039      $nextIndicator && $nextIndicator.addClass('active')
44040    }
44041
44042    var slidEvent = $.Event('slid.bs.carousel', { relatedTarget: relatedTarget, direction: direction }) // yes, "slid"
44043    if ($.support.transition && this.$element.hasClass('slide')) {
44044      $next.addClass(type)
44045      $next[0].offsetWidth // force reflow
44046      $active.addClass(direction)
44047      $next.addClass(direction)
44048      $active
44049        .one('bsTransitionEnd', function () {
44050          $next.removeClass([type, direction].join(' ')).addClass('active')
44051          $active.removeClass(['active', direction].join(' '))
44052          that.sliding = false
44053          setTimeout(function () {
44054            that.$element.trigger(slidEvent)
44055          }, 0)
44056        })
44057        .emulateTransitionEnd(Carousel.TRANSITION_DURATION)
44058    } else {
44059      $active.removeClass('active')
44060      $next.addClass('active')
44061      this.sliding = false
44062      this.$element.trigger(slidEvent)
44063    }
44064
44065    isCycling && this.cycle()
44066
44067    return this
44068  }
44069
44070
44071  // CAROUSEL PLUGIN DEFINITION
44072  // ==========================
44073
44074  function Plugin(option) {
44075    return this.each(function () {
44076      var $this   = $(this)
44077      var data    = $this.data('bs.carousel')
44078      var options = $.extend({}, Carousel.DEFAULTS, $this.data(), typeof option == 'object' && option)
44079      var action  = typeof option == 'string' ? option : options.slide
44080
44081      if (!data) $this.data('bs.carousel', (data = new Carousel(this, options)))
44082      if (typeof option == 'number') data.to(option)
44083      else if (action) data[action]()
44084      else if (options.interval) data.pause().cycle()
44085    })
44086  }
44087
44088  var old = $.fn.carousel
44089
44090  $.fn.carousel             = Plugin
44091  $.fn.carousel.Constructor = Carousel
44092
44093
44094  // CAROUSEL NO CONFLICT
44095  // ====================
44096
44097  $.fn.carousel.noConflict = function () {
44098    $.fn.carousel = old
44099    return this
44100  }
44101
44102
44103  // CAROUSEL DATA-API
44104  // =================
44105
44106  var clickHandler = function (e) {
44107    var href
44108    var $this   = $(this)
44109    var $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) // strip for ie7
44110    if (!$target.hasClass('carousel')) return
44111    var options = $.extend({}, $target.data(), $this.data())
44112    var slideIndex = $this.attr('data-slide-to')
44113    if (slideIndex) options.interval = false
44114
44115    Plugin.call($target, options)
44116
44117    if (slideIndex) {
44118      $target.data('bs.carousel').to(slideIndex)
44119    }
44120
44121    e.preventDefault()
44122  }
44123
44124  $(document)
44125    .on('click.bs.carousel.data-api', '[data-slide]', clickHandler)
44126    .on('click.bs.carousel.data-api', '[data-slide-to]', clickHandler)
44127
44128  $(window).on('load', function () {
44129    $('[data-ride="carousel"]').each(function () {
44130      var $carousel = $(this)
44131      Plugin.call($carousel, $carousel.data())
44132    })
44133  })
44134
44135}(jQuery);
44136
44137/* ========================================================================
44138 * Bootstrap: collapse.js v3.3.7
44139 * http://getbootstrap.com/javascript/#collapse
44140 * ========================================================================
44141 * Copyright 2011-2016 Twitter, Inc.
44142 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
44143 * ======================================================================== */
44144
44145/* jshint latedef: false */
44146
44147+function ($) {
44148  'use strict';
44149
44150  // COLLAPSE PUBLIC CLASS DEFINITION
44151  // ================================
44152
44153  var Collapse = function (element, options) {
44154    this.$element      = $(element)
44155    this.options       = $.extend({}, Collapse.DEFAULTS, options)
44156    this.$trigger      = $('[data-toggle="collapse"][href="#' + element.id + '"],' +
44157                           '[data-toggle="collapse"][data-target="#' + element.id + '"]')
44158    this.transitioning = null
44159
44160    if (this.options.parent) {
44161      this.$parent = this.getParent()
44162    } else {
44163      this.addAriaAndCollapsedClass(this.$element, this.$trigger)
44164    }
44165
44166    if (this.options.toggle) this.toggle()
44167  }
44168
44169  Collapse.VERSION  = '3.3.7'
44170
44171  Collapse.TRANSITION_DURATION = 350
44172
44173  Collapse.DEFAULTS = {
44174    toggle: true
44175  }
44176
44177  Collapse.prototype.dimension = function () {
44178    var hasWidth = this.$element.hasClass('width')
44179    return hasWidth ? 'width' : 'height'
44180  }
44181
44182  Collapse.prototype.show = function () {
44183    if (this.transitioning || this.$element.hasClass('in')) return
44184
44185    var activesData
44186    var actives = this.$parent && this.$parent.children('.panel').children('.in, .collapsing')
44187
44188    if (actives && actives.length) {
44189      activesData = actives.data('bs.collapse')
44190      if (activesData && activesData.transitioning) return
44191    }
44192
44193    var startEvent = $.Event('show.bs.collapse')
44194    this.$element.trigger(startEvent)
44195    if (startEvent.isDefaultPrevented()) return
44196
44197    if (actives && actives.length) {
44198      Plugin.call(actives, 'hide')
44199      activesData || actives.data('bs.collapse', null)
44200    }
44201
44202    var dimension = this.dimension()
44203
44204    this.$element
44205      .removeClass('collapse')
44206      .addClass('collapsing')[dimension](0)
44207      .attr('aria-expanded', true)
44208
44209    this.$trigger
44210      .removeClass('collapsed')
44211      .attr('aria-expanded', true)
44212
44213    this.transitioning = 1
44214
44215    var complete = function () {
44216      this.$element
44217        .removeClass('collapsing')
44218        .addClass('collapse in')[dimension]('')
44219      this.transitioning = 0
44220      this.$element
44221        .trigger('shown.bs.collapse')
44222    }
44223
44224    if (!$.support.transition) return complete.call(this)
44225
44226    var scrollSize = $.camelCase(['scroll', dimension].join('-'))
44227
44228    this.$element
44229      .one('bsTransitionEnd', $.proxy(complete, this))
44230      .emulateTransitionEnd(Collapse.TRANSITION_DURATION)[dimension](this.$element[0][scrollSize])
44231  }
44232
44233  Collapse.prototype.hide = function () {
44234    if (this.transitioning || !this.$element.hasClass('in')) return
44235
44236    var startEvent = $.Event('hide.bs.collapse')
44237    this.$element.trigger(startEvent)
44238    if (startEvent.isDefaultPrevented()) return
44239
44240    var dimension = this.dimension()
44241
44242    this.$element[dimension](this.$element[dimension]())[0].offsetHeight
44243
44244    this.$element
44245      .addClass('collapsing')
44246      .removeClass('collapse in')
44247      .attr('aria-expanded', false)
44248
44249    this.$trigger
44250      .addClass('collapsed')
44251      .attr('aria-expanded', false)
44252
44253    this.transitioning = 1
44254
44255    var complete = function () {
44256      this.transitioning = 0
44257      this.$element
44258        .removeClass('collapsing')
44259        .addClass('collapse')
44260        .trigger('hidden.bs.collapse')
44261    }
44262
44263    if (!$.support.transition) return complete.call(this)
44264
44265    this.$element
44266      [dimension](0)
44267      .one('bsTransitionEnd', $.proxy(complete, this))
44268      .emulateTransitionEnd(Collapse.TRANSITION_DURATION)
44269  }
44270
44271  Collapse.prototype.toggle = function () {
44272    this[this.$element.hasClass('in') ? 'hide' : 'show']()
44273  }
44274
44275  Collapse.prototype.getParent = function () {
44276    return $(this.options.parent)
44277      .find('[data-toggle="collapse"][data-parent="' + this.options.parent + '"]')
44278      .each($.proxy(function (i, element) {
44279        var $element = $(element)
44280        this.addAriaAndCollapsedClass(getTargetFromTrigger($element), $element)
44281      }, this))
44282      .end()
44283  }
44284
44285  Collapse.prototype.addAriaAndCollapsedClass = function ($element, $trigger) {
44286    var isOpen = $element.hasClass('in')
44287
44288    $element.attr('aria-expanded', isOpen)
44289    $trigger
44290      .toggleClass('collapsed', !isOpen)
44291      .attr('aria-expanded', isOpen)
44292  }
44293
44294  function getTargetFromTrigger($trigger) {
44295    var href
44296    var target = $trigger.attr('data-target')
44297      || (href = $trigger.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') // strip for ie7
44298
44299    return $(target)
44300  }
44301
44302
44303  // COLLAPSE PLUGIN DEFINITION
44304  // ==========================
44305
44306  function Plugin(option) {
44307    return this.each(function () {
44308      var $this   = $(this)
44309      var data    = $this.data('bs.collapse')
44310      var options = $.extend({}, Collapse.DEFAULTS, $this.data(), typeof option == 'object' && option)
44311
44312      if (!data && options.toggle && /show|hide/.test(option)) options.toggle = false
44313      if (!data) $this.data('bs.collapse', (data = new Collapse(this, options)))
44314      if (typeof option == 'string') data[option]()
44315    })
44316  }
44317
44318  var old = $.fn.collapse
44319
44320  $.fn.collapse             = Plugin
44321  $.fn.collapse.Constructor = Collapse
44322
44323
44324  // COLLAPSE NO CONFLICT
44325  // ====================
44326
44327  $.fn.collapse.noConflict = function () {
44328    $.fn.collapse = old
44329    return this
44330  }
44331
44332
44333  // COLLAPSE DATA-API
44334  // =================
44335
44336  $(document).on('click.bs.collapse.data-api', '[data-toggle="collapse"]', function (e) {
44337    var $this   = $(this)
44338
44339    if (!$this.attr('data-target')) e.preventDefault()
44340
44341    var $target = getTargetFromTrigger($this)
44342    var data    = $target.data('bs.collapse')
44343    var option  = data ? 'toggle' : $this.data()
44344
44345    Plugin.call($target, option)
44346  })
44347
44348}(jQuery);
44349
44350/* ========================================================================
44351 * Bootstrap: dropdown.js v3.3.7
44352 * http://getbootstrap.com/javascript/#dropdowns
44353 * ========================================================================
44354 * Copyright 2011-2016 Twitter, Inc.
44355 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
44356 * ======================================================================== */
44357
44358
44359+function ($) {
44360  'use strict';
44361
44362  // DROPDOWN CLASS DEFINITION
44363  // =========================
44364
44365  var backdrop = '.dropdown-backdrop'
44366  var toggle   = '[data-toggle="dropdown"]'
44367  var Dropdown = function (element) {
44368    $(element).on('click.bs.dropdown', this.toggle)
44369  }
44370
44371  Dropdown.VERSION = '3.3.7'
44372
44373  function getParent($this) {
44374    var selector = $this.attr('data-target')
44375
44376    if (!selector) {
44377      selector = $this.attr('href')
44378      selector = selector && /#[A-Za-z]/.test(selector) && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7
44379    }
44380
44381    var $parent = selector && $(selector)
44382
44383    return $parent && $parent.length ? $parent : $this.parent()
44384  }
44385
44386  function clearMenus(e) {
44387    if (e && e.which === 3) return
44388    $(backdrop).remove()
44389    $(toggle).each(function () {
44390      var $this         = $(this)
44391      var $parent       = getParent($this)
44392      var relatedTarget = { relatedTarget: this }
44393
44394      if (!$parent.hasClass('open')) return
44395
44396      if (e && e.type == 'click' && /input|textarea/i.test(e.target.tagName) && $.contains($parent[0], e.target)) return
44397
44398      $parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
44399
44400      if (e.isDefaultPrevented()) return
44401
44402      $this.attr('aria-expanded', 'false')
44403      $parent.removeClass('open').trigger($.Event('hidden.bs.dropdown', relatedTarget))
44404    })
44405  }
44406
44407  Dropdown.prototype.toggle = function (e) {
44408    var $this = $(this)
44409
44410    if ($this.is('.disabled, :disabled')) return
44411
44412    var $parent  = getParent($this)
44413    var isActive = $parent.hasClass('open')
44414
44415    clearMenus()
44416
44417    if (!isActive) {
44418      if ('ontouchstart' in document.documentElement && !$parent.closest('.navbar-nav').length) {
44419        // if mobile we use a backdrop because click events don't delegate
44420        $(document.createElement('div'))
44421          .addClass('dropdown-backdrop')
44422          .insertAfter($(this))
44423          .on('click', clearMenus)
44424      }
44425
44426      var relatedTarget = { relatedTarget: this }
44427      $parent.trigger(e = $.Event('show.bs.dropdown', relatedTarget))
44428
44429      if (e.isDefaultPrevented()) return
44430
44431      $this
44432        .trigger('focus')
44433        .attr('aria-expanded', 'true')
44434
44435      $parent
44436        .toggleClass('open')
44437        .trigger($.Event('shown.bs.dropdown', relatedTarget))
44438    }
44439
44440    return false
44441  }
44442
44443  Dropdown.prototype.keydown = function (e) {
44444    if (!/(38|40|27|32)/.test(e.which) || /input|textarea/i.test(e.target.tagName)) return
44445
44446    var $this = $(this)
44447
44448    e.preventDefault()
44449    e.stopPropagation()
44450
44451    if ($this.is('.disabled, :disabled')) return
44452
44453    var $parent  = getParent($this)
44454    var isActive = $parent.hasClass('open')
44455
44456    if (!isActive && e.which != 27 || isActive && e.which == 27) {
44457      if (e.which == 27) $parent.find(toggle).trigger('focus')
44458      return $this.trigger('click')
44459    }
44460
44461    var desc = ' li:not(.disabled):visible a'
44462    var $items = $parent.find('.dropdown-menu' + desc)
44463
44464    if (!$items.length) return
44465
44466    var index = $items.index(e.target)
44467
44468    if (e.which == 38 && index > 0)                 index--         // up
44469    if (e.which == 40 && index < $items.length - 1) index++         // down
44470    if (!~index)                                    index = 0
44471
44472    $items.eq(index).trigger('focus')
44473  }
44474
44475
44476  // DROPDOWN PLUGIN DEFINITION
44477  // ==========================
44478
44479  function Plugin(option) {
44480    return this.each(function () {
44481      var $this = $(this)
44482      var data  = $this.data('bs.dropdown')
44483
44484      if (!data) $this.data('bs.dropdown', (data = new Dropdown(this)))
44485      if (typeof option == 'string') data[option].call($this)
44486    })
44487  }
44488
44489  var old = $.fn.dropdown
44490
44491  $.fn.dropdown             = Plugin
44492  $.fn.dropdown.Constructor = Dropdown
44493
44494
44495  // DROPDOWN NO CONFLICT
44496  // ====================
44497
44498  $.fn.dropdown.noConflict = function () {
44499    $.fn.dropdown = old
44500    return this
44501  }
44502
44503
44504  // APPLY TO STANDARD DROPDOWN ELEMENTS
44505  // ===================================
44506
44507  $(document)
44508    .on('click.bs.dropdown.data-api', clearMenus)
44509    .on('click.bs.dropdown.data-api', '.dropdown form', function (e) { e.stopPropagation() })
44510    .on('click.bs.dropdown.data-api', toggle, Dropdown.prototype.toggle)
44511    .on('keydown.bs.dropdown.data-api', toggle, Dropdown.prototype.keydown)
44512    .on('keydown.bs.dropdown.data-api', '.dropdown-menu', Dropdown.prototype.keydown)
44513
44514}(jQuery);
44515
44516/* ========================================================================
44517 * Bootstrap: modal.js v3.3.7
44518 * http://getbootstrap.com/javascript/#modals
44519 * ========================================================================
44520 * Copyright 2011-2016 Twitter, Inc.
44521 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
44522 * ======================================================================== */
44523
44524
44525+function ($) {
44526  'use strict';
44527
44528  // MODAL CLASS DEFINITION
44529  // ======================
44530
44531  var Modal = function (element, options) {
44532    this.options             = options
44533    this.$body               = $(document.body)
44534    this.$element            = $(element)
44535    this.$dialog             = this.$element.find('.modal-dialog')
44536    this.$backdrop           = null
44537    this.isShown             = null
44538    this.originalBodyPad     = null
44539    this.scrollbarWidth      = 0
44540    this.ignoreBackdropClick = false
44541
44542    if (this.options.remote) {
44543      this.$element
44544        .find('.modal-content')
44545        .load(this.options.remote, $.proxy(function () {
44546          this.$element.trigger('loaded.bs.modal')
44547        }, this))
44548    }
44549  }
44550
44551  Modal.VERSION  = '3.3.7'
44552
44553  Modal.TRANSITION_DURATION = 300
44554  Modal.BACKDROP_TRANSITION_DURATION = 150
44555
44556  Modal.DEFAULTS = {
44557    backdrop: true,
44558    keyboard: true,
44559    show: true
44560  }
44561
44562  Modal.prototype.toggle = function (_relatedTarget) {
44563    return this.isShown ? this.hide() : this.show(_relatedTarget)
44564  }
44565
44566  Modal.prototype.show = function (_relatedTarget) {
44567    var that = this
44568    var e    = $.Event('show.bs.modal', { relatedTarget: _relatedTarget })
44569
44570    this.$element.trigger(e)
44571
44572    if (this.isShown || e.isDefaultPrevented()) return
44573
44574    this.isShown = true
44575
44576    this.checkScrollbar()
44577    this.setScrollbar()
44578    this.$body.addClass('modal-open')
44579
44580    this.escape()
44581    this.resize()
44582
44583    this.$element.on('click.dismiss.bs.modal', '[data-dismiss="modal"]', $.proxy(this.hide, this))
44584
44585    this.$dialog.on('mousedown.dismiss.bs.modal', function () {
44586      that.$element.one('mouseup.dismiss.bs.modal', function (e) {
44587        if ($(e.target).is(that.$element)) that.ignoreBackdropClick = true
44588      })
44589    })
44590
44591    this.backdrop(function () {
44592      var transition = $.support.transition && that.$element.hasClass('fade')
44593
44594      if (!that.$element.parent().length) {
44595        that.$element.appendTo(that.$body) // don't move modals dom position
44596      }
44597
44598      that.$element
44599        .show()
44600        .scrollTop(0)
44601
44602      that.adjustDialog()
44603
44604      if (transition) {
44605        that.$element[0].offsetWidth // force reflow
44606      }
44607
44608      that.$element.addClass('in')
44609
44610      that.enforceFocus()
44611
44612      var e = $.Event('shown.bs.modal', { relatedTarget: _relatedTarget })
44613
44614      transition ?
44615        that.$dialog // wait for modal to slide in
44616          .one('bsTransitionEnd', function () {
44617            that.$element.trigger('focus').trigger(e)
44618          })
44619          .emulateTransitionEnd(Modal.TRANSITION_DURATION) :
44620        that.$element.trigger('focus').trigger(e)
44621    })
44622  }
44623
44624  Modal.prototype.hide = function (e) {
44625    if (e) e.preventDefault()
44626
44627    e = $.Event('hide.bs.modal')
44628
44629    this.$element.trigger(e)
44630
44631    if (!this.isShown || e.isDefaultPrevented()) return
44632
44633    this.isShown = false
44634
44635    this.escape()
44636    this.resize()
44637
44638    $(document).off('focusin.bs.modal')
44639
44640    this.$element
44641      .removeClass('in')
44642      .off('click.dismiss.bs.modal')
44643      .off('mouseup.dismiss.bs.modal')
44644
44645    this.$dialog.off('mousedown.dismiss.bs.modal')
44646
44647    $.support.transition && this.$element.hasClass('fade') ?
44648      this.$element
44649        .one('bsTransitionEnd', $.proxy(this.hideModal, this))
44650        .emulateTransitionEnd(Modal.TRANSITION_DURATION) :
44651      this.hideModal()
44652  }
44653
44654  Modal.prototype.enforceFocus = function () {
44655    $(document)
44656      .off('focusin.bs.modal') // guard against infinite focus loop
44657      .on('focusin.bs.modal', $.proxy(function (e) {
44658        if (document !== e.target &&
44659            this.$element[0] !== e.target &&
44660            !this.$element.has(e.target).length) {
44661          this.$element.trigger('focus')
44662        }
44663      }, this))
44664  }
44665
44666  Modal.prototype.escape = function () {
44667    if (this.isShown && this.options.keyboard) {
44668      this.$element.on('keydown.dismiss.bs.modal', $.proxy(function (e) {
44669        e.which == 27 && this.hide()
44670      }, this))
44671    } else if (!this.isShown) {
44672      this.$element.off('keydown.dismiss.bs.modal')
44673    }
44674  }
44675
44676  Modal.prototype.resize = function () {
44677    if (this.isShown) {
44678      $(window).on('resize.bs.modal', $.proxy(this.handleUpdate, this))
44679    } else {
44680      $(window).off('resize.bs.modal')
44681    }
44682  }
44683
44684  Modal.prototype.hideModal = function () {
44685    var that = this
44686    this.$element.hide()
44687    this.backdrop(function () {
44688      that.$body.removeClass('modal-open')
44689      that.resetAdjustments()
44690      that.resetScrollbar()
44691      that.$element.trigger('hidden.bs.modal')
44692    })
44693  }
44694
44695  Modal.prototype.removeBackdrop = function () {
44696    this.$backdrop && this.$backdrop.remove()
44697    this.$backdrop = null
44698  }
44699
44700  Modal.prototype.backdrop = function (callback) {
44701    var that = this
44702    var animate = this.$element.hasClass('fade') ? 'fade' : ''
44703
44704    if (this.isShown && this.options.backdrop) {
44705      var doAnimate = $.support.transition && animate
44706
44707      this.$backdrop = $(document.createElement('div'))
44708        .addClass('modal-backdrop ' + animate)
44709        .appendTo(this.$body)
44710
44711      this.$element.on('click.dismiss.bs.modal', $.proxy(function (e) {
44712        if (this.ignoreBackdropClick) {
44713          this.ignoreBackdropClick = false
44714          return
44715        }
44716        if (e.target !== e.currentTarget) return
44717        this.options.backdrop == 'static'
44718          ? this.$element[0].focus()
44719          : this.hide()
44720      }, this))
44721
44722      if (doAnimate) this.$backdrop[0].offsetWidth // force reflow
44723
44724      this.$backdrop.addClass('in')
44725
44726      if (!callback) return
44727
44728      doAnimate ?
44729        this.$backdrop
44730          .one('bsTransitionEnd', callback)
44731          .emulateTransitionEnd(Modal.BACKDROP_TRANSITION_DURATION) :
44732        callback()
44733
44734    } else if (!this.isShown && this.$backdrop) {
44735      this.$backdrop.removeClass('in')
44736
44737      var callbackRemove = function () {
44738        that.removeBackdrop()
44739        callback && callback()
44740      }
44741      $.support.transition && this.$element.hasClass('fade') ?
44742        this.$backdrop
44743          .one('bsTransitionEnd', callbackRemove)
44744          .emulateTransitionEnd(Modal.BACKDROP_TRANSITION_DURATION) :
44745        callbackRemove()
44746
44747    } else if (callback) {
44748      callback()
44749    }
44750  }
44751
44752  // these following methods are used to handle overflowing modals
44753
44754  Modal.prototype.handleUpdate = function () {
44755    this.adjustDialog()
44756  }
44757
44758  Modal.prototype.adjustDialog = function () {
44759    var modalIsOverflowing = this.$element[0].scrollHeight > document.documentElement.clientHeight
44760
44761    this.$element.css({
44762      paddingLeft:  !this.bodyIsOverflowing && modalIsOverflowing ? this.scrollbarWidth : '',
44763      paddingRight: this.bodyIsOverflowing && !modalIsOverflowing ? this.scrollbarWidth : ''
44764    })
44765  }
44766
44767  Modal.prototype.resetAdjustments = function () {
44768    this.$element.css({
44769      paddingLeft: '',
44770      paddingRight: ''
44771    })
44772  }
44773
44774  Modal.prototype.checkScrollbar = function () {
44775    var fullWindowWidth = window.innerWidth
44776    if (!fullWindowWidth) { // workaround for missing window.innerWidth in IE8
44777      var documentElementRect = document.documentElement.getBoundingClientRect()
44778      fullWindowWidth = documentElementRect.right - Math.abs(documentElementRect.left)
44779    }
44780    this.bodyIsOverflowing = document.body.clientWidth < fullWindowWidth
44781    this.scrollbarWidth = this.measureScrollbar()
44782  }
44783
44784  Modal.prototype.setScrollbar = function () {
44785    var bodyPad = parseInt((this.$body.css('padding-right') || 0), 10)
44786    this.originalBodyPad = document.body.style.paddingRight || ''
44787    if (this.bodyIsOverflowing) this.$body.css('padding-right', bodyPad + this.scrollbarWidth)
44788  }
44789
44790  Modal.prototype.resetScrollbar = function () {
44791    this.$body.css('padding-right', this.originalBodyPad)
44792  }
44793
44794  Modal.prototype.measureScrollbar = function () { // thx walsh
44795    var scrollDiv = document.createElement('div')
44796    scrollDiv.className = 'modal-scrollbar-measure'
44797    this.$body.append(scrollDiv)
44798    var scrollbarWidth = scrollDiv.offsetWidth - scrollDiv.clientWidth
44799    this.$body[0].removeChild(scrollDiv)
44800    return scrollbarWidth
44801  }
44802
44803
44804  // MODAL PLUGIN DEFINITION
44805  // =======================
44806
44807  function Plugin(option, _relatedTarget) {
44808    return this.each(function () {
44809      var $this   = $(this)
44810      var data    = $this.data('bs.modal')
44811      var options = $.extend({}, Modal.DEFAULTS, $this.data(), typeof option == 'object' && option)
44812
44813      if (!data) $this.data('bs.modal', (data = new Modal(this, options)))
44814      if (typeof option == 'string') data[option](_relatedTarget)
44815      else if (options.show) data.show(_relatedTarget)
44816    })
44817  }
44818
44819  var old = $.fn.modal
44820
44821  $.fn.modal             = Plugin
44822  $.fn.modal.Constructor = Modal
44823
44824
44825  // MODAL NO CONFLICT
44826  // =================
44827
44828  $.fn.modal.noConflict = function () {
44829    $.fn.modal = old
44830    return this
44831  }
44832
44833
44834  // MODAL DATA-API
44835  // ==============
44836
44837  $(document).on('click.bs.modal.data-api', '[data-toggle="modal"]', function (e) {
44838    var $this   = $(this)
44839    var href    = $this.attr('href')
44840    var $target = $($this.attr('data-target') || (href && href.replace(/.*(?=#[^\s]+$)/, ''))) // strip for ie7
44841    var option  = $target.data('bs.modal') ? 'toggle' : $.extend({ remote: !/#/.test(href) && href }, $target.data(), $this.data())
44842
44843    if ($this.is('a')) e.preventDefault()
44844
44845    $target.one('show.bs.modal', function (showEvent) {
44846      if (showEvent.isDefaultPrevented()) return // only register focus restorer if modal will actually get shown
44847      $target.one('hidden.bs.modal', function () {
44848        $this.is(':visible') && $this.trigger('focus')
44849      })
44850    })
44851    Plugin.call($target, option, this)
44852  })
44853
44854}(jQuery);
44855
44856/* ========================================================================
44857 * Bootstrap: tooltip.js v3.3.7
44858 * http://getbootstrap.com/javascript/#tooltip
44859 * Inspired by the original jQuery.tipsy by Jason Frame
44860 * ========================================================================
44861 * Copyright 2011-2016 Twitter, Inc.
44862 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
44863 * ======================================================================== */
44864
44865
44866+function ($) {
44867  'use strict';
44868
44869  // TOOLTIP PUBLIC CLASS DEFINITION
44870  // ===============================
44871
44872  var Tooltip = function (element, options) {
44873    this.type       = null
44874    this.options    = null
44875    this.enabled    = null
44876    this.timeout    = null
44877    this.hoverState = null
44878    this.$element   = null
44879    this.inState    = null
44880
44881    this.init('tooltip', element, options)
44882  }
44883
44884  Tooltip.VERSION  = '3.3.7'
44885
44886  Tooltip.TRANSITION_DURATION = 150
44887
44888  Tooltip.DEFAULTS = {
44889    animation: true,
44890    placement: 'top',
44891    selector: false,
44892    template: '<div class="tooltip" role="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>',
44893    trigger: 'hover focus',
44894    title: '',
44895    delay: 0,
44896    html: false,
44897    container: false,
44898    viewport: {
44899      selector: 'body',
44900      padding: 0
44901    }
44902  }
44903
44904  Tooltip.prototype.init = function (type, element, options) {
44905    this.enabled   = true
44906    this.type      = type
44907    this.$element  = $(element)
44908    this.options   = this.getOptions(options)
44909    this.$viewport = this.options.viewport && $($.isFunction(this.options.viewport) ? this.options.viewport.call(this, this.$element) : (this.options.viewport.selector || this.options.viewport))
44910    this.inState   = { click: false, hover: false, focus: false }
44911
44912    if (this.$element[0] instanceof document.constructor && !this.options.selector) {
44913      throw new Error('`selector` option must be specified when initializing ' + this.type + ' on the window.document object!')
44914    }
44915
44916    var triggers = this.options.trigger.split(' ')
44917
44918    for (var i = triggers.length; i--;) {
44919      var trigger = triggers[i]
44920
44921      if (trigger == 'click') {
44922        this.$element.on('click.' + this.type, this.options.selector, $.proxy(this.toggle, this))
44923      } else if (trigger != 'manual') {
44924        var eventIn  = trigger == 'hover' ? 'mouseenter' : 'focusin'
44925        var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'
44926
44927        this.$element.on(eventIn  + '.' + this.type, this.options.selector, $.proxy(this.enter, this))
44928        this.$element.on(eventOut + '.' + this.type, this.options.selector, $.proxy(this.leave, this))
44929      }
44930    }
44931
44932    this.options.selector ?
44933      (this._options = $.extend({}, this.options, { trigger: 'manual', selector: '' })) :
44934      this.fixTitle()
44935  }
44936
44937  Tooltip.prototype.getDefaults = function () {
44938    return Tooltip.DEFAULTS
44939  }
44940
44941  Tooltip.prototype.getOptions = function (options) {
44942    options = $.extend({}, this.getDefaults(), this.$element.data(), options)
44943
44944    if (options.delay && typeof options.delay == 'number') {
44945      options.delay = {
44946        show: options.delay,
44947        hide: options.delay
44948      }
44949    }
44950
44951    return options
44952  }
44953
44954  Tooltip.prototype.getDelegateOptions = function () {
44955    var options  = {}
44956    var defaults = this.getDefaults()
44957
44958    this._options && $.each(this._options, function (key, value) {
44959      if (defaults[key] != value) options[key] = value
44960    })
44961
44962    return options
44963  }
44964
44965  Tooltip.prototype.enter = function (obj) {
44966    var self = obj instanceof this.constructor ?
44967      obj : $(obj.currentTarget).data('bs.' + this.type)
44968
44969    if (!self) {
44970      self = new this.constructor(obj.currentTarget, this.getDelegateOptions())
44971      $(obj.currentTarget).data('bs.' + this.type, self)
44972    }
44973
44974    if (obj instanceof $.Event) {
vendor: 9,753 bytes, lines 44975-45253
44975      self.inState[obj.type == 'focusin' ? 'focus' : 'hover'] = true
44976    }
44977
44978    if (self.tip().hasClass('in') || self.hoverState == 'in') {
44979      self.hoverState = 'in'
44980      return
44981    }
44982
44983    clearTimeout(self.timeout)
44984
44985    self.hoverState = 'in'
44986
44987    if (!self.options.delay || !self.options.delay.show) return self.show()
44988
44989    self.timeout = setTimeout(function () {
44990      if (self.hoverState == 'in') self.show()
44991    }, self.options.delay.show)
44992  }
44993
44994  Tooltip.prototype.isInStateTrue = function () {
44995    for (var key in this.inState) {
44996      if (this.inState[key]) return true
44997    }
44998
44999    return false
45000  }
45001
45002  Tooltip.prototype.leave = function (obj) {
45003    var self = obj instanceof this.constructor ?
45004      obj : $(obj.currentTarget).data('bs.' + this.type)
45005
45006    if (!self) {
45007      self = new this.constructor(obj.currentTarget, this.getDelegateOptions())
45008      $(obj.currentTarget).data('bs.' + this.type, self)
45009    }
45010
45011    if (obj instanceof $.Event) {
45012      self.inState[obj.type == 'focusout' ? 'focus' : 'hover'] = false
45013    }
45014
45015    if (self.isInStateTrue()) return
45016
45017    clearTimeout(self.timeout)
45018
45019    self.hoverState = 'out'
45020
45021    if (!self.options.delay || !self.options.delay.hide) return self.hide()
45022
45023    self.timeout = setTimeout(function () {
45024      if (self.hoverState == 'out') self.hide()
45025    }, self.options.delay.hide)
45026  }
45027
45028  Tooltip.prototype.show = function () {
45029    var e = $.Event('show.bs.' + this.type)
45030
45031    if (this.hasContent() && this.enabled) {
45032      this.$element.trigger(e)
45033
45034      var inDom = $.contains(this.$element[0].ownerDocument.documentElement, this.$element[0])
45035      if (e.isDefaultPrevented() || !inDom) return
45036      var that = this
45037
45038      var $tip = this.tip()
45039
45040      var tipId = this.getUID(this.type)
45041
45042      this.setContent()
45043      $tip.attr('id', tipId)
45044      this.$element.attr('aria-describedby', tipId)
45045
45046      if (this.options.animation) $tip.addClass('fade')
45047
45048      var placement = typeof this.options.placement == 'function' ?
45049        this.options.placement.call(this, $tip[0], this.$element[0]) :
45050        this.options.placement
45051
45052      var autoToken = /\s?auto?\s?/i
45053      var autoPlace = autoToken.test(placement)
45054      if (autoPlace) placement = placement.replace(autoToken, '') || 'top'
45055
45056      $tip
45057        .detach()
45058        .css({ top: 0, left: 0, display: 'block' })
45059        .addClass(placement)
45060        .data('bs.' + this.type, this)
45061
45062      this.options.container ? $tip.appendTo(this.options.container) : $tip.insertAfter(this.$element)
45063      this.$element.trigger('inserted.bs.' + this.type)
45064
45065      var pos          = this.getPosition()
45066      var actualWidth  = $tip[0].offsetWidth
45067      var actualHeight = $tip[0].offsetHeight
45068
45069      if (autoPlace) {
45070        var orgPlacement = placement
45071        var viewportDim = this.getPosition(this.$viewport)
45072
45073        placement = placement == 'bottom' && pos.bottom + actualHeight > viewportDim.bottom ? 'top'    :
45074                    placement == 'top'    && pos.top    - actualHeight < viewportDim.top    ? 'bottom' :
45075                    placement == 'right'  && pos.right  + actualWidth  > viewportDim.width  ? 'left'   :
45076                    placement == 'left'   && pos.left   - actualWidth  < viewportDim.left   ? 'right'  :
45077                    placement
45078
45079        $tip
45080          .removeClass(orgPlacement)
45081          .addClass(placement)
45082      }
45083
45084      var calculatedOffset = this.getCalculatedOffset(placement, pos, actualWidth, actualHeight)
45085
45086      this.applyPlacement(calculatedOffset, placement)
45087
45088      var complete = function () {
45089        var prevHoverState = that.hoverState
45090        that.$element.trigger('shown.bs.' + that.type)
45091        that.hoverState = null
45092
45093        if (prevHoverState == 'out') that.leave(that)
45094      }
45095
45096      $.support.transition && this.$tip.hasClass('fade') ?
45097        $tip
45098          .one('bsTransitionEnd', complete)
45099          .emulateTransitionEnd(Tooltip.TRANSITION_DURATION) :
45100        complete()
45101    }
45102  }
45103
45104  Tooltip.prototype.applyPlacement = function (offset, placement) {
45105    var $tip   = this.tip()
45106    var width  = $tip[0].offsetWidth
45107    var height = $tip[0].offsetHeight
45108
45109    // manually read margins because getBoundingClientRect includes difference
45110    var marginTop = parseInt($tip.css('margin-top'), 10)
45111    var marginLeft = parseInt($tip.css('margin-left'), 10)
45112
45113    // we must check for NaN for ie 8/9
45114    if (isNaN(marginTop))  marginTop  = 0
45115    if (isNaN(marginLeft)) marginLeft = 0
45116
45117    offset.top  += marginTop
45118    offset.left += marginLeft
45119
45120    // $.fn.offset doesn't round pixel values
45121    // so we use setOffset directly with our own function B-0
45122    $.offset.setOffset($tip[0], $.extend({
45123      using: function (props) {
45124        $tip.css({
45125          top: Math.round(props.top),
45126          left: Math.round(props.left)
45127        })
45128      }
45129    }, offset), 0)
45130
45131    $tip.addClass('in')
45132
45133    // check to see if placing tip in new offset caused the tip to resize itself
45134    var actualWidth  = $tip[0].offsetWidth
45135    var actualHeight = $tip[0].offsetHeight
45136
45137    if (placement == 'top' && actualHeight != height) {
45138      offset.top = offset.top + height - actualHeight
45139    }
45140
45141    var delta = this.getViewportAdjustedDelta(placement, offset, actualWidth, actualHeight)
45142
45143    if (delta.left) offset.left += delta.left
45144    else offset.top += delta.top
45145
45146    var isVertical          = /top|bottom/.test(placement)
45147    var arrowDelta          = isVertical ? delta.left * 2 - width + actualWidth : delta.top * 2 - height + actualHeight
45148    var arrowOffsetPosition = isVertical ? 'offsetWidth' : 'offsetHeight'
45149
45150    $tip.offset(offset)
45151    this.replaceArrow(arrowDelta, $tip[0][arrowOffsetPosition], isVertical)
45152  }
45153
45154  Tooltip.prototype.replaceArrow = function (delta, dimension, isVertical) {
45155    this.arrow()
45156      .css(isVertical ? 'left' : 'top', 50 * (1 - delta / dimension) + '%')
45157      .css(isVertical ? 'top' : 'left', '')
45158  }
45159
45160  Tooltip.prototype.setContent = function () {
45161    var $tip  = this.tip()
45162    var title = this.getTitle()
45163
45164    $tip.find('.tooltip-inner')[this.options.html ? 'html' : 'text'](title)
45165    $tip.removeClass('fade in top bottom left right')
45166  }
45167
45168  Tooltip.prototype.hide = function (callback) {
45169    var that = this
45170    var $tip = $(this.$tip)
45171    var e    = $.Event('hide.bs.' + this.type)
45172
45173    function complete() {
45174      if (that.hoverState != 'in') $tip.detach()
45175      if (that.$element) { // TODO: Check whether guarding this code with this `if` is really necessary.
45176        that.$element
45177          .removeAttr('aria-describedby')
45178          .trigger('hidden.bs.' + that.type)
45179      }
45180      callback && callback()
45181    }
45182
45183    this.$element.trigger(e)
45184
45185    if (e.isDefaultPrevented()) return
45186
45187    $tip.removeClass('in')
45188
45189    $.support.transition && $tip.hasClass('fade') ?
45190      $tip
45191        .one('bsTransitionEnd', complete)
45192        .emulateTransitionEnd(Tooltip.TRANSITION_DURATION) :
45193      complete()
45194
45195    this.hoverState = null
45196
45197    return this
45198  }
45199
45200  Tooltip.prototype.fixTitle = function () {
45201    var $e = this.$element
45202    if ($e.attr('title') || typeof $e.attr('data-original-title') != 'string') {
45203      $e.attr('data-original-title', $e.attr('title') || '').attr('title', '')
45204    }
45205  }
45206
45207  Tooltip.prototype.hasContent = function () {
45208    return this.getTitle()
45209  }
45210
45211  Tooltip.prototype.getPosition = function ($element) {
45212    $element   = $element || this.$element
45213
45214    var el     = $element[0]
45215    var isBody = el.tagName == 'BODY'
45216
45217    var elRect    = el.getBoundingClientRect()
45218    if (elRect.width == null) {
45219      // width and height are missing in IE8, so compute them manually; see https://github.com/twbs/bootstrap/issues/14093
45220      elRect = $.extend({}, elRect, { width: elRect.right - elRect.left, height: elRect.bottom - elRect.top })
45221    }
45222    var isSvg = window.SVGElement && el instanceof window.SVGElement
45223    // Avoid using $.offset() on SVGs since it gives incorrect results in jQuery 3.
45224    // See https://github.com/twbs/bootstrap/issues/20280
45225    var elOffset  = isBody ? { top: 0, left: 0 } : (isSvg ? null : $element.offset())
45226    var scroll    = { scroll: isBody ? document.documentElement.scrollTop || document.body.scrollTop : $element.scrollTop() }
45227    var outerDims = isBody ? { width: $(window).width(), height: $(window).height() } : null
45228
45229    return $.extend({}, elRect, scroll, outerDims, elOffset)
45230  }
45231
45232  Tooltip.prototype.getCalculatedOffset = function (placement, pos, actualWidth, actualHeight) {
45233    return placement == 'bottom' ? { top: pos.top + pos.height,   left: pos.left + pos.width / 2 - actualWidth / 2 } :
45234           placement == 'top'    ? { top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2 } :
45235           placement == 'left'   ? { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth } :
45236        /* placement == 'right' */ { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width }
45237
45238  }
45239
45240  Tooltip.prototype.getViewportAdjustedDelta = function (placement, pos, actualWidth, actualHeight) {
45241    var delta = { top: 0, left: 0 }
45242    if (!this.$viewport) return delta
45243
45244    var viewportPadding = this.options.viewport && this.options.viewport.padding || 0
45245    var viewportDimensions = this.getPosition(this.$viewport)
45246
45247    if (/right|left/.test(placement)) {
45248      var topEdgeOffset    = pos.top - viewportPadding - viewportDimensions.scroll
45249      var bottomEdgeOffset = pos.top + viewportPadding - viewportDimensions.scroll + actualHeight
45250      if (topEdgeOffset < viewportDimensions.top) { // top overflow
45251        delta.top = viewportDimensions.top - topEdgeOffset
45252      } else if (bottomEdgeOffset > viewportDimensions.top + viewportDimensions.height) { // bottom overflow
45253        delta.top = viewportDimensions.top + viewportDimensions.height - bottom
vendor: 19,773 bytes, lines 45253-45976
45253EdgeOffset
45254      }
45255    } else {
45256      var leftEdgeOffset  = pos.left - viewportPadding
45257      var rightEdgeOffset = pos.left + viewportPadding + actualWidth
45258      if (leftEdgeOffset < viewportDimensions.left) { // left overflow
45259        delta.left = viewportDimensions.left - leftEdgeOffset
45260      } else if (rightEdgeOffset > viewportDimensions.right) { // right overflow
45261        delta.left = viewportDimensions.left + viewportDimensions.width - rightEdgeOffset
45262      }
45263    }
45264
45265    return delta
45266  }
45267
45268  Tooltip.prototype.getTitle = function () {
45269    var title
45270    var $e = this.$element
45271    var o  = this.options
45272
45273    title = $e.attr('data-original-title')
45274      || (typeof o.title == 'function' ? o.title.call($e[0]) :  o.title)
45275
45276    return title
45277  }
45278
45279  Tooltip.prototype.getUID = function (prefix) {
45280    do prefix += ~~(Math.random() * 1000000)
45281    while (document.getElementById(prefix))
45282    return prefix
45283  }
45284
45285  Tooltip.prototype.tip = function () {
45286    if (!this.$tip) {
45287      this.$tip = $(this.options.template)
45288      if (this.$tip.length != 1) {
45289        throw new Error(this.type + ' `template` option must consist of exactly 1 top-level element!')
45290      }
45291    }
45292    return this.$tip
45293  }
45294
45295  Tooltip.prototype.arrow = function () {
45296    return (this.$arrow = this.$arrow || this.tip().find('.tooltip-arrow'))
45297  }
45298
45299  Tooltip.prototype.enable = function () {
45300    this.enabled = true
45301  }
45302
45303  Tooltip.prototype.disable = function () {
45304    this.enabled = false
45305  }
45306
45307  Tooltip.prototype.toggleEnabled = function () {
45308    this.enabled = !this.enabled
45309  }
45310
45311  Tooltip.prototype.toggle = function (e) {
45312    var self = this
45313    if (e) {
45314      self = $(e.currentTarget).data('bs.' + this.type)
45315      if (!self) {
45316        self = new this.constructor(e.currentTarget, this.getDelegateOptions())
45317        $(e.currentTarget).data('bs.' + this.type, self)
45318      }
45319    }
45320
45321    if (e) {
45322      self.inState.click = !self.inState.click
45323      if (self.isInStateTrue()) self.enter(self)
45324      else self.leave(self)
45325    } else {
45326      self.tip().hasClass('in') ? self.leave(self) : self.enter(self)
45327    }
45328  }
45329
45330  Tooltip.prototype.destroy = function () {
45331    var that = this
45332    clearTimeout(this.timeout)
45333    this.hide(function () {
45334      that.$element.off('.' + that.type).removeData('bs.' + that.type)
45335      if (that.$tip) {
45336        that.$tip.detach()
45337      }
45338      that.$tip = null
45339      that.$arrow = null
45340      that.$viewport = null
45341      that.$element = null
45342    })
45343  }
45344
45345
45346  // TOOLTIP PLUGIN DEFINITION
45347  // =========================
45348
45349  function Plugin(option) {
45350    return this.each(function () {
45351      var $this   = $(this)
45352      var data    = $this.data('bs.tooltip')
45353      var options = typeof option == 'object' && option
45354
45355      if (!data && /destroy|hide/.test(option)) return
45356      if (!data) $this.data('bs.tooltip', (data = new Tooltip(this, options)))
45357      if (typeof option == 'string') data[option]()
45358    })
45359  }
45360
45361  var old = $.fn.tooltip
45362
45363  $.fn.tooltip             = Plugin
45364  $.fn.tooltip.Constructor = Tooltip
45365
45366
45367  // TOOLTIP NO CONFLICT
45368  // ===================
45369
45370  $.fn.tooltip.noConflict = function () {
45371    $.fn.tooltip = old
45372    return this
45373  }
45374
45375}(jQuery);
45376
45377/* ========================================================================
45378 * Bootstrap: popover.js v3.3.7
45379 * http://getbootstrap.com/javascript/#popovers
45380 * ========================================================================
45381 * Copyright 2011-2016 Twitter, Inc.
45382 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
45383 * ======================================================================== */
45384
45385
45386+function ($) {
45387  'use strict';
45388
45389  // POPOVER PUBLIC CLASS DEFINITION
45390  // ===============================
45391
45392  var Popover = function (element, options) {
45393    this.init('popover', element, options)
45394  }
45395
45396  if (!$.fn.tooltip) throw new Error('Popover requires tooltip.js')
45397
45398  Popover.VERSION  = '3.3.7'
45399
45400  Popover.DEFAULTS = $.extend({}, $.fn.tooltip.Constructor.DEFAULTS, {
45401    placement: 'right',
45402    trigger: 'click',
45403    content: '',
45404    template: '<div class="popover" role="tooltip"><div class="arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>'
45405  })
45406
45407
45408  // NOTE: POPOVER EXTENDS tooltip.js
45409  // ================================
45410
45411  Popover.prototype = $.extend({}, $.fn.tooltip.Constructor.prototype)
45412
45413  Popover.prototype.constructor = Popover
45414
45415  Popover.prototype.getDefaults = function () {
45416    return Popover.DEFAULTS
45417  }
45418
45419  Popover.prototype.setContent = function () {
45420    var $tip    = this.tip()
45421    var title   = this.getTitle()
45422    var content = this.getContent()
45423
45424    $tip.find('.popover-title')[this.options.html ? 'html' : 'text'](title)
45425    $tip.find('.popover-content').children().detach().end()[ // we use append for html objects to maintain js events
45426      this.options.html ? (typeof content == 'string' ? 'html' : 'append') : 'text'
45427    ](content)
45428
45429    $tip.removeClass('fade top bottom left right in')
45430
45431    // IE8 doesn't accept hiding via the `:empty` pseudo selector, we have to do
45432    // this manually by checking the contents.
45433    if (!$tip.find('.popover-title').html()) $tip.find('.popover-title').hide()
45434  }
45435
45436  Popover.prototype.hasContent = function () {
45437    return this.getTitle() || this.getContent()
45438  }
45439
45440  Popover.prototype.getContent = function () {
45441    var $e = this.$element
45442    var o  = this.options
45443
45444    return $e.attr('data-content')
45445      || (typeof o.content == 'function' ?
45446            o.content.call($e[0]) :
45447            o.content)
45448  }
45449
45450  Popover.prototype.arrow = function () {
45451    return (this.$arrow = this.$arrow || this.tip().find('.arrow'))
45452  }
45453
45454
45455  // POPOVER PLUGIN DEFINITION
45456  // =========================
45457
45458  function Plugin(option) {
45459    return this.each(function () {
45460      var $this   = $(this)
45461      var data    = $this.data('bs.popover')
45462      var options = typeof option == 'object' && option
45463
45464      if (!data && /destroy|hide/.test(option)) return
45465      if (!data) $this.data('bs.popover', (data = new Popover(this, options)))
45466      if (typeof option == 'string') data[option]()
45467    })
45468  }
45469
45470  var old = $.fn.popover
45471
45472  $.fn.popover             = Plugin
45473  $.fn.popover.Constructor = Popover
45474
45475
45476  // POPOVER NO CONFLICT
45477  // ===================
45478
45479  $.fn.popover.noConflict = function () {
45480    $.fn.popover = old
45481    return this
45482  }
45483
45484}(jQuery);
45485
45486/* ========================================================================
45487 * Bootstrap: scrollspy.js v3.3.7
45488 * http://getbootstrap.com/javascript/#scrollspy
45489 * ========================================================================
45490 * Copyright 2011-2016 Twitter, Inc.
45491 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
45492 * ======================================================================== */
45493
45494
45495+function ($) {
45496  'use strict';
45497
45498  // SCROLLSPY CLASS DEFINITION
45499  // ==========================
45500
45501  function ScrollSpy(element, options) {
45502    this.$body          = $(document.body)
45503    this.$scrollElement = $(element).is(document.body) ? $(window) : $(element)
45504    this.options        = $.extend({}, ScrollSpy.DEFAULTS, options)
45505    this.selector       = (this.options.target || '') + ' .nav li > a'
45506    this.offsets        = []
45507    this.targets        = []
45508    this.activeTarget   = null
45509    this.scrollHeight   = 0
45510
45511    this.$scrollElement.on('scroll.bs.scrollspy', $.proxy(this.process, this))
45512    this.refresh()
45513    this.process()
45514  }
45515
45516  ScrollSpy.VERSION  = '3.3.7'
45517
45518  ScrollSpy.DEFAULTS = {
45519    offset: 10
45520  }
45521
45522  ScrollSpy.prototype.getScrollHeight = function () {
45523    return this.$scrollElement[0].scrollHeight || Math.max(this.$body[0].scrollHeight, document.documentElement.scrollHeight)
45524  }
45525
45526  ScrollSpy.prototype.refresh = function () {
45527    var that          = this
45528    var offsetMethod  = 'offset'
45529    var offsetBase    = 0
45530
45531    this.offsets      = []
45532    this.targets      = []
45533    this.scrollHeight = this.getScrollHeight()
45534
45535    if (!$.isWindow(this.$scrollElement[0])) {
45536      offsetMethod = 'position'
45537      offsetBase   = this.$scrollElement.scrollTop()
45538    }
45539
45540    this.$body
45541      .find(this.selector)
45542      .map(function () {
45543        var $el   = $(this)
45544        var href  = $el.data('target') || $el.attr('href')
45545        var $href = /^#./.test(href) && $(href)
45546
45547        return ($href
45548          && $href.length
45549          && $href.is(':visible')
45550          && [[$href[offsetMethod]().top + offsetBase, href]]) || null
45551      })
45552      .sort(function (a, b) { return a[0] - b[0] })
45553      .each(function () {
45554        that.offsets.push(this[0])
45555        that.targets.push(this[1])
45556      })
45557  }
45558
45559  ScrollSpy.prototype.process = function () {
45560    var scrollTop    = this.$scrollElement.scrollTop() + this.options.offset
45561    var scrollHeight = this.getScrollHeight()
45562    var maxScroll    = this.options.offset + scrollHeight - this.$scrollElement.height()
45563    var offsets      = this.offsets
45564    var targets      = this.targets
45565    var activeTarget = this.activeTarget
45566    var i
45567
45568    if (this.scrollHeight != scrollHeight) {
45569      this.refresh()
45570    }
45571
45572    if (scrollTop >= maxScroll) {
45573      return activeTarget != (i = targets[targets.length - 1]) && this.activate(i)
45574    }
45575
45576    if (activeTarget && scrollTop < offsets[0]) {
45577      this.activeTarget = null
45578      return this.clear()
45579    }
45580
45581    for (i = offsets.length; i--;) {
45582      activeTarget != targets[i]
45583        && scrollTop >= offsets[i]
45584        && (offsets[i + 1] === undefined || scrollTop < offsets[i + 1])
45585        && this.activate(targets[i])
45586    }
45587  }
45588
45589  ScrollSpy.prototype.activate = function (target) {
45590    this.activeTarget = target
45591
45592    this.clear()
45593
45594    var selector = this.selector +
45595      '[data-target="' + target + '"],' +
45596      this.selector + '[href="' + target + '"]'
45597
45598    var active = $(selector)
45599      .parents('li')
45600      .addClass('active')
45601
45602    if (active.parent('.dropdown-menu').length) {
45603      active = active
45604        .closest('li.dropdown')
45605        .addClass('active')
45606    }
45607
45608    active.trigger('activate.bs.scrollspy')
45609  }
45610
45611  ScrollSpy.prototype.clear = function () {
45612    $(this.selector)
45613      .parentsUntil(this.options.target, '.active')
45614      .removeClass('active')
45615  }
45616
45617
45618  // SCROLLSPY PLUGIN DEFINITION
45619  // ===========================
45620
45621  function Plugin(option) {
45622    return this.each(function () {
45623      var $this   = $(this)
45624      var data    = $this.data('bs.scrollspy')
45625      var options = typeof option == 'object' && option
45626
45627      if (!data) $this.data('bs.scrollspy', (data = new ScrollSpy(this, options)))
45628      if (typeof option == 'string') data[option]()
45629    })
45630  }
45631
45632  var old = $.fn.scrollspy
45633
45634  $.fn.scrollspy             = Plugin
45635  $.fn.scrollspy.Constructor = ScrollSpy
45636
45637
45638  // SCROLLSPY NO CONFLICT
45639  // =====================
45640
45641  $.fn.scrollspy.noConflict = function () {
45642    $.fn.scrollspy = old
45643    return this
45644  }
45645
45646
45647  // SCROLLSPY DATA-API
45648  // ==================
45649
45650  $(window).on('load.bs.scrollspy.data-api', function () {
45651    $('[data-spy="scroll"]').each(function () {
45652      var $spy = $(this)
45653      Plugin.call($spy, $spy.data())
45654    })
45655  })
45656
45657}(jQuery);
45658
45659/* ========================================================================
45660 * Bootstrap: tab.js v3.3.7
45661 * http://getbootstrap.com/javascript/#tabs
45662 * ========================================================================
45663 * Copyright 2011-2016 Twitter, Inc.
45664 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
45665 * ======================================================================== */
45666
45667
45668+function ($) {
45669  'use strict';
45670
45671  // TAB CLASS DEFINITION
45672  // ====================
45673
45674  var Tab = function (element) {
45675    // jscs:disable requireDollarBeforejQueryAssignment
45676    this.element = $(element)
45677    // jscs:enable requireDollarBeforejQueryAssignment
45678  }
45679
45680  Tab.VERSION = '3.3.7'
45681
45682  Tab.TRANSITION_DURATION = 150
45683
45684  Tab.prototype.show = function () {
45685    var $this    = this.element
45686    var $ul      = $this.closest('ul:not(.dropdown-menu)')
45687    var selector = $this.data('target')
45688
45689    if (!selector) {
45690      selector = $this.attr('href')
45691      selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7
45692    }
45693
45694    if ($this.parent('li').hasClass('active')) return
45695
45696    var $previous = $ul.find('.active:last a')
45697    var hideEvent = $.Event('hide.bs.tab', {
45698      relatedTarget: $this[0]
45699    })
45700    var showEvent = $.Event('show.bs.tab', {
45701      relatedTarget: $previous[0]
45702    })
45703
45704    $previous.trigger(hideEvent)
45705    $this.trigger(showEvent)
45706
45707    if (showEvent.isDefaultPrevented() || hideEvent.isDefaultPrevented()) return
45708
45709    var $target = $(selector)
45710
45711    this.activate($this.closest('li'), $ul)
45712    this.activate($target, $target.parent(), function () {
45713      $previous.trigger({
45714        type: 'hidden.bs.tab',
45715        relatedTarget: $this[0]
45716      })
45717      $this.trigger({
45718        type: 'shown.bs.tab',
45719        relatedTarget: $previous[0]
45720      })
45721    })
45722  }
45723
45724  Tab.prototype.activate = function (element, container, callback) {
45725    var $active    = container.find('> .active')
45726    var transition = callback
45727      && $.support.transition
45728      && ($active.length && $active.hasClass('fade') || !!container.find('> .fade').length)
45729
45730    function next() {
45731      $active
45732        .removeClass('active')
45733        .find('> .dropdown-menu > .active')
45734          .removeClass('active')
45735        .end()
45736        .find('[data-toggle="tab"]')
45737          .attr('aria-expanded', false)
45738
45739      element
45740        .addClass('active')
45741        .find('[data-toggle="tab"]')
45742          .attr('aria-expanded', true)
45743
45744      if (transition) {
45745        element[0].offsetWidth // reflow for transition
45746        element.addClass('in')
45747      } else {
45748        element.removeClass('fade')
45749      }
45750
45751      if (element.parent('.dropdown-menu').length) {
45752        element
45753          .closest('li.dropdown')
45754            .addClass('active')
45755          .end()
45756          .find('[data-toggle="tab"]')
45757            .attr('aria-expanded', true)
45758      }
45759
45760      callback && callback()
45761    }
45762
45763    $active.length && transition ?
45764      $active
45765        .one('bsTransitionEnd', next)
45766        .emulateTransitionEnd(Tab.TRANSITION_DURATION) :
45767      next()
45768
45769    $active.removeClass('in')
45770  }
45771
45772
45773  // TAB PLUGIN DEFINITION
45774  // =====================
45775
45776  function Plugin(option) {
45777    return this.each(function () {
45778      var $this = $(this)
45779      var data  = $this.data('bs.tab')
45780
45781      if (!data) $this.data('bs.tab', (data = new Tab(this)))
45782      if (typeof option == 'string') data[option]()
45783    })
45784  }
45785
45786  var old = $.fn.tab
45787
45788  $.fn.tab             = Plugin
45789  $.fn.tab.Constructor = Tab
45790
45791
45792  // TAB NO CONFLICT
45793  // ===============
45794
45795  $.fn.tab.noConflict = function () {
45796    $.fn.tab = old
45797    return this
45798  }
45799
45800
45801  // TAB DATA-API
45802  // ============
45803
45804  var clickHandler = function (e) {
45805    e.preventDefault()
45806    Plugin.call($(this), 'show')
45807  }
45808
45809  $(document)
45810    .on('click.bs.tab.data-api', '[data-toggle="tab"]', clickHandler)
45811    .on('click.bs.tab.data-api', '[data-toggle="pill"]', clickHandler)
45812
45813}(jQuery);
45814
45815/* ========================================================================
45816 * Bootstrap: affix.js v3.3.7
45817 * http://getbootstrap.com/javascript/#affix
45818 * ========================================================================
45819 * Copyright 2011-2016 Twitter, Inc.
45820 * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
45821 * ======================================================================== */
45822
45823
45824+function ($) {
45825  'use strict';
45826
45827  // AFFIX CLASS DEFINITION
45828  // ======================
45829
45830  var Affix = function (element, options) {
45831    this.options = $.extend({}, Affix.DEFAULTS, options)
45832
45833    this.$target = $(this.options.target)
45834      .on('scroll.bs.affix.data-api', $.proxy(this.checkPosition, this))
45835      .on('click.bs.affix.data-api',  $.proxy(this.checkPositionWithEventLoop, this))
45836
45837    this.$element     = $(element)
45838    this.affixed      = null
45839    this.unpin        = null
45840    this.pinnedOffset = null
45841
45842    this.checkPosition()
45843  }
45844
45845  Affix.VERSION  = '3.3.7'
45846
45847  Affix.RESET    = 'affix affix-top affix-bottom'
45848
45849  Affix.DEFAULTS = {
45850    offset: 0,
45851    target: window
45852  }
45853
45854  Affix.prototype.getState = function (scrollHeight, height, offsetTop, offsetBottom) {
45855    var scrollTop    = this.$target.scrollTop()
45856    var position     = this.$element.offset()
45857    var targetHeight = this.$target.height()
45858
45859    if (offsetTop != null && this.affixed == 'top') return scrollTop < offsetTop ? 'top' : false
45860
45861    if (this.affixed == 'bottom') {
45862      if (offsetTop != null) return (scrollTop + this.unpin <= position.top) ? false : 'bottom'
45863      return (scrollTop + targetHeight <= scrollHeight - offsetBottom) ? false : 'bottom'
45864    }
45865
45866    var initializing   = this.affixed == null
45867    var colliderTop    = initializing ? scrollTop : position.top
45868    var colliderHeight = initializing ? targetHeight : height
45869
45870    if (offsetTop != null && scrollTop <= offsetTop) return 'top'
45871    if (offsetBottom != null && (colliderTop + colliderHeight >= scrollHeight - offsetBottom)) return 'bottom'
45872
45873    return false
45874  }
45875
45876  Affix.prototype.getPinnedOffset = function () {
45877    if (this.pinnedOffset) return this.pinnedOffset
45878    this.$element.removeClass(Affix.RESET).addClass('affix')
45879    var scrollTop = this.$target.scrollTop()
45880    var position  = this.$element.offset()
45881    return (this.pinnedOffset = position.top - scrollTop)
45882  }
45883
45884  Affix.prototype.checkPositionWithEventLoop = function () {
45885    setTimeout($.proxy(this.checkPosition, this), 1)
45886  }
45887
45888  Affix.prototype.checkPosition = function () {
45889    if (!this.$element.is(':visible')) return
45890
45891    var height       = this.$element.height()
45892    var offset       = this.options.offset
45893    var offsetTop    = offset.top
45894    var offsetBottom = offset.bottom
45895    var scrollHeight = Math.max($(document).height(), $(document.body).height())
45896
45897    if (typeof offset != 'object')         offsetBottom = offsetTop = offset
45898    if (typeof offsetTop == 'function')    offsetTop    = offset.top(this.$element)
45899    if (typeof offsetBottom == 'function') offsetBottom = offset.bottom(this.$element)
45900
45901    var affix = this.getState(scrollHeight, height, offsetTop, offsetBottom)
45902
45903    if (this.affixed != affix) {
45904      if (this.unpin != null) this.$element.css('top', '')
45905
45906      var affixType = 'affix' + (affix ? '-' + affix : '')
45907      var e         = $.Event(affixType + '.bs.affix')
45908
45909      this.$element.trigger(e)
45910
45911      if (e.isDefaultPrevented()) return
45912
45913      this.affixed = affix
45914      this.unpin = affix == 'bottom' ? this.getPinnedOffset() : null
45915
45916      this.$element
45917        .removeClass(Affix.RESET)
45918        .addClass(affixType)
45919        .trigger(affixType.replace('affix', 'affixed') + '.bs.affix')
45920    }
45921
45922    if (affix == 'bottom') {
45923      this.$element.offset({
45924        top: scrollHeight - height - offsetBottom
45925      })
45926    }
45927  }
45928
45929
45930  // AFFIX PLUGIN DEFINITION
45931  // =======================
45932
45933  function Plugin(option) {
45934    return this.each(function () {
45935      var $this   = $(this)
45936      var data    = $this.data('bs.affix')
45937      var options = typeof option == 'object' && option
45938
45939      if (!data) $this.data('bs.affix', (data = new Affix(this, options)))
45940      if (typeof option == 'string') data[option]()
45941    })
45942  }
45943
45944  var old = $.fn.affix
45945
45946  $.fn.affix             = Plugin
45947  $.fn.affix.Constructor = Affix
45948
45949
45950  // AFFIX NO CONFLICT
45951  // =================
45952
45953  $.fn.affix.noConflict = function () {
45954    $.fn.affix = old
45955    return this
45956  }
45957
45958
45959  // AFFIX DATA-API
45960  // ==============
45961
45962  $(window).on('load', function () {
45963    $('[data-spy="affix"]').each(function () {
45964      var $spy = $(this)
45965      var data = $spy.data()
45966
45967      data.offset = data.offset || {}
45968
45969      if (data.offsetBottom != null) data.offset.bottom = data.offsetBottom
45970      if (data.offsetTop    != null) data.offset.top    = data.offsetTop
45971
45972      Plugin.call($spy, data)
45973    })
45974  })
45975
45976}(jQuery);
45977
45978angular.module('NanoPlayer', [])
45979  .service('NanoPlayerService', function () {
45980    var service = {};
45981
45982    service.playerCss = `
45983      .nano-player panel {
45984        display: block;
45985        margin: 0px auto;
45986        padding: 5px;
45987        font-size: 40px;
45988      }
45989      .nano-player button {
45990        display: inline-block;
45991        background: none;
45992        border: none;
45993        padding: 3px 0px;
45994        cursor: pointer;
45995        font-size: 40px;
45996        transition: all 0.2s;
45997      }
45998      .nano-player button:hover {
45999        opacity: 0.5;
46000      }
46001    `;
46002
46003    service.panel = `
46004    <panel>
46005      <button act="play" class="fa fa-play-circle"></button>
46006      <button act="pause" class="fa fa-pause-circle"></button>
46007      <button act="reset" class="fa fa-rotate-left"></button>
46008    </panel>
46009    `;
46010
46011    service.forward = `<button act="forward" class="fa fa-forward ml10"></button>`;
46012    service.rewind = `<button act="back" class="fa fa-backward mr10"></button>`;
46013
46014    service.installStyle = function () {
46015      if (!$('#nano-player-css').length) {
46016        $('<style></style>')
46017          .attr('id', 'nano-player-css')
46018          .attr('type', 'text/css')
46019          .append(service.playerCss)
46020          .appendTo('head');
46021      }
46022    }
46023    return service;
46024  })
46025  .directive('mp3Player', ['NanoPlayerService', function (NanoPlayerService) {
46026    return {
46027      restrict: 'E',
46028      template: (c, attr) => `<audio ng-src="${attr.src}" type="audio/mp3"></audio>`,
46029      link: (scope, element, attributes) => {
46030        NanoPlayerService.installStyle();
46031        $(element).addClass('nano-player').append(NanoPlayerService.panel);
46032
46033        let player = $(element).find('audio').get(0);
46034        let buttons = $(element).find('button');
46035
46036        buttons.filter('[act="play"]').click((e) => player.play());
46037        buttons.filter('[act="pause"]').click((e) => player.pause());
46038        buttons.filter('[act="reset"]').click((e) => player.currentTime = 0);
46039      }
46040    }
46041  }])
46042  .directive('mp4Player', ['NanoPlayerService', function (NanoPlayerService) {
46043    return {
46044      restrict: 'E',
46045      template: (c, attr) => `<video ng-src="${attr.src}" type="video/mpeg"></video>`,
46046      link: (scope, element, attributes) => {
46047        NanoPlayerService.installStyle();
46048        $(element).addClass('nano-player').append(NanoPlayerService.panel);
46049        if (attributes.extended) $(element).find('panel').prepend(NanoPlayerService.rewind).append(NanoPlayerService.forward);
46050        if (attributes.poster) $(element).find('video').attr('poster', attributes.poster);
46051
46052        let player = $(element).find('video').get(0);
46053        let buttons = $(element).find('button');
46054
46055        $(player).click(function () { player.play(); })
46056
46057        buttons.filter('[act="play"]').click((e) => player.play());
46058        buttons.filter('[act="pause"]').click((e) => player.pause());
46059        buttons.filter('[act="reset"]').click((e) => player.currentTime = 0);
46060        buttons.filter('[act="forward"]').click((e) => player.currentTime = player.currentTime + 5);
46061        buttons.filter('[act="back"]').click((e) => player.currentTime = player.currentTime - 5);
46062      }
46063    }
46064  }]);

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